Why must virtual base classes be constructed by the most derived class?
Solution 1:
Because it avoids this:
class A {
public:
A(int) {}
};
class B0: virtual public A {
public:
B0(): A(0) {}
};
class B1: virtual public A {
public:
B1(): A(1) {}
};
class C: public B0, public B1 {
public:
C() {} // How is A constructed? A(0) from B0 or A(1) from B1?
};
Solution 2:
Because in the class hierarchy having a virtually inherited base class, the base class would/may be shared by multiple classes (in diamond inheritance for example, where the same base class is inherited by multiple classes). It means, there would be only one copy of the virtually-inherited base class. It essentially means, the base class must be constructed first. It eventually means the derived class must instantiate the given base class.
For example:
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 // A is shared, and would have one copy only.
Solution 3:
I find this rule error-prone and cumbersome (but then, what part of multiple inheritance isn't?).
But the logically imposed order of construction must differ from the case of normal (non-virtual) inheritance. Consider Ajay's example, minus virtual:
class A;
class B1 : A;
class B2 : A;
class C: B1,B2
In this case for each C two As are constructed, one as part of B1, the other one as part of B2. The code of the B classes is responsible for that, and can do it. The order of events is:
Start C ctor
Start B1 ctor
A ctor (in B's ctor code)
End B1 ctor
Start B2 ctor
A ctor (in B's ctor code)
End B2 ctor
End C ctor
Now consider virtual inheritance in
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2
One order of event is
Start C ctor
A ctor // not B's code!
Start B1 ctor
// NO A ctor
End B1 ctor
Start B2 ctor
// NO A ctor
End B2 ctor
End C ctor
The important logical distinction is that the virtually inherited base class sub-object of type A is part of the most derived class and under the control of it (here C
).
B's constructors know nothing about and cannot access A
. Consequently they cannot construct sub-objects of A
, including base classes.