What is the construction order in a "diamond problem" where a class is derived from three base classes?
Below is an example code of what I am asking. The output will be XXbBACY, but I don't understand why.
#include <iostream>
using namespace std;
class X {
public:
X() { cout << 'X'; }
X(char c) { cout << 'X' << c; }
};
class A : virtual X {
public:
A() : X('a') { cout << 'A'; }
};
class B : X {
public:
B() : X('b') { cout << 'B'; }
};
class C : virtual X {
public:
C() : X('c') { cout << 'C'; }
};
class Y : A, virtual B, C {
public:
Y() { cout << 'Y'; }
~Y() {}
};
int main() {
Y y;
return 0;
}
From my understanding, when we create the object y of class Y, because not all the base classes are virtually derived from the class X (B specifically), Y will have 3 instances of class X in it.
The first constructor called when constructing the object y will be the constructor of class B because it is virtually derived from class Y, but before constructing the class B, an instance of class X will have to be created and because
B() : X('b') { cout << 'B'; }
is the default constructor of class B, X(char c) { cout << 'X' << c; }
will be called in class X. Which will print Xb. Now we return to class B where the default constructor will print B, and then back to class Y
Now an instance of class A and class C will similarly be constructed leaving us with an output of: XbBXaAXcCY
My understanding seems to be completely wrong, because the output is XXbBACY, how can this be?
Solution 1:
Construction order is always this:
- First all (direct or indirect) virtual bases, ordered depth-first declaration-order. Obviously at most one of any type.
- Next, the non-virtual bases in declaration order.
- All other members in declaration order.
- Finally, the ctor body. Now you may safely call virtual functions, directly or indirectly, and they will resolve based on the currently running ctor.
In your case that means:
-
virtual X
fromY::A::X
. -
virtual B
fromY::B
:
(First step:X
fromY::B::X
.) -
A
fromY::A
.X
virtual base already done. -
C
fromY::C
.X
virtual base already done.
Destruction order reverses that.