I've started learning about virtual inheritance (and how it may solve problems of having a class derived from two parent classes with same parent). To better understand the mechanism behind it, i made a following example:
class A {
public:
A(string text = "Constructor A") { cout << text << endl; }
};
class B: public A {
public:
B(): A("A called from B") { cout << "Constructor B" << endl; }
};
class C : virtual public A {
public:
C() : A("A called from C") { cout << "Constructor C" << endl; }
};
class D : public B, public C {
public:
D() { cout << "Constructor D" << endl; }
};
I have class A
, class B
derived from A
, class C
virtually derived from A
, and class D
derived from B
and C
. In main i just form an object of class D
: D d;
and i get the following output
Constructor A
A called from B
Constructor B
Constructor C
Constructor D
What bothers me is, why is there "Constructor A" signalizing that it is not called by either class B
or C
. And why is there not "A called from C" before "Constructor C". For the latter one i know it has to do with the class C
being virtually derived so i guess it does not call Constructor A
again since object from class A
has already been formed (twice in fact).
EDIT:
In main i just make one object type D.
int main() {
D d;
}
Firstly, since B
derives from A
non-virtually, D
ends up with two A
subobjects (as if you didn't use virtual
inheritance at all).
The non-virtual A
is constructed by B()
(hence "A called from B"
), and the virtual one prints "Constructor A"
when constructed.
That's because the constructors of virtual (possibly indirect) bases are always called by the constructor of the most derived class (D
), rather than by the constructors of any intermediate bases (C
).
It means that : A("A called from C")
in C()
is ignored (since you're not constructing a standalone C
). And since D()
doesn't mention A
in its member initializer list, the virtual A
is constructed without any parameters (as if by : A()
).
Also, it's worth mentioning that all virtual bases are constructed before the non-virtual ones.
So your code is guaranteed to print Constructor A
before A called from B
.