Reputation: 153
I have couple question regarding how the following code runs
using namespace std;
class A
{
int i;
public:
A() { i = 7; cout << 1 << f() << i; }
A(int i) :i(i) { cout << 1 << f() << i; }
char f() { return 'A'; }
};
class B : public virtual A
{
int i;
public:
B(int i) : A(i), i(++i) { cout << 2 << i; }
virtual char f() { return 'B'; }
};
class C : public virtual A {
public:
C(int i) : A(i) { cout << 3 << i; }
virtual char f() { return 'C'; }
};
class D :public A {
public:
D(int i) { cout << 4 << i; }
virtual char f() { return 'D'; }
};
class E : public B, public C, public D {
public:
E() : B(2), C(3), D(4) { cout << 5; }
virtual char f() { return 'E'; }
};
int main()
{
E e;
return 0;
}
So the output should be '1A723331A7445'.
Upvotes: 2
Views: 61
Reputation: 170044
Right, so let me start off by saying you've created a truly messed up type hierarchy. If you were trying to understand initialization order, this example is only likely to confuse you.
Anyway, to make things clearer, I modified your code and added a slash /
character to the end of each c'tor print statement. So we can more easily discern what part of the line belongs to each c'tor. This gives the following output:
1A7/23/33/1A7/44/5
Before I get to the initialization order, you should know that all the virtual functions you specified won't by dynamically dispatched. A virtual function in the c'tor body will be statically bound. So for our intents and purposes, you don't really have virtual functions called in your code.
Now, to quote the C++ standard, this is how the initialization order will be determined ([class.base.init]/13):
In a non-delegating constructor, initialization proceeds in the following order:
First, and only for the constructor of the most derived class, 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.
Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
Finally, the compound-statement of the constructor body is executed.
So let's break your initialization apart:
1) The virtual A
sub-object is default constructed, since you didn't specify it in the member initializer list of E()
, it executes A()
for the object that is shared for B
and C
, and prints 1A7/
.
2) Now the c'tor for B
is called, executing B(int i)
with i = 2
. It sets B::i
to 3
, and the c'tor body prints 23/
.
3) C
is constructed by calling C(int i)
with i = 3
. This prints 33/
.
4) Now it's time to construct D
. So you call D(int i)
with i = 4
. Since D
inherits from A
non-virtually, it will have a distinct A
sub-object that needs construction now.
You again didn't specify a parameter for it in the member initializer list, so A
is default constructed. This prints 1A7/
.
Now the body of D(int i)
runs, and prints 44/
.
5) Finally, the body of E()
is called, and prints 5
.
Upvotes: 1