I have three classes as you can see in the code below. Notice how I have written the copy constructors.
#include <iostream>
class Abstract
{
public:
Abstract(){};
Abstract( const Abstract& other ): mA(other.mA){};
virtual ~Abstract(){};
void setA(double inA){mA = inA;};
double getA(){return mA;};
virtual void isAbstract() = 0;
protected:
double mA;
};
class Parent : public virtual Abstract
{
public:
Parent(){};
Parent( const Parent& other ): Abstract(other){};
virtual ~Parent(){};
};
class Child : public virtual Parent
{
public:
Child(){};
Child( const Child& other ): Parent(other){};
virtual ~Child(){};
void isAbstract(){};
};
int main()
{
Child child1;
child1.setA(5);
Child childCopy(child1);
std::cout << childCopy.getA() << std::endl;
return 0;
}
Now why Abstract()
gets called instead of the copy constructor Abstract( const Abstract& other )
when childCopy
is being constructed?
Shouldn't Child(other)
call Parent(other)
? And shouldn't Parent(other)
in turn call Abstract(other)
?
Virtual base classes can only be initialized by the most derived class. Calls to a constructor of a virtual base from a non most-derived class are ignored and replaced with default constructor calls. This is to ensure that the virtual base subobject is initialized only once:
The correct code should place the constructor call in the most derived class' ctor-initializer :
Child(Child const& other)
: Abstract(other) // indirect virtual bases are
// initialized first
, Parent(other) // followed by direct bases
{ }
In order to have correctly called Abstract
's copy constructor, you need to specify that in the initializer list of Child
's copy constructor.
Child( const Child& other ): Abstract(other), Parent(other) {};
Here is the relevant quote from the standard, which states that the constructor of a virtual base class is called only in the most derived class. If it is missing, the default constructor is called instead (--if it exists).
§12.6.2, (13.1):
In a non-delegating constructor, initialization proceeds in the following order:
- First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
In particular, this is why you notice Abstract
's default constructor being called.
In order to avoid this pitfall, however, you can drop all user-defined copy constructors and rely on the copy constructor which is implicitly defined (which is always a good idea). DEMO 2
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.