Virtual inheritance behavior in this case

I wrote this program with virtual inheritance and I have a few questions.

#include<iostream> using namespace std; class B1 { public: B1() { cout << "In B1 constructor\n"; } }; class V1 : public B1 { public: V1() { cout << "In V1 constructor\n"; } }; class D1 : virtual public V1 { public: D1() { cout << "In D1 constructor\n"; } }; class B2 { public: B2() { cout << "In B2 constructor\n"; } }; class B3 { public: B3() { cout << "In B3 constructor\n"; } }; class V2 : public B1, public B2 { public: V2() { cout << "In V2 constructor\n"; } }; class D2 : public B3, virtual public V2 { public: D2() { cout << "In D2 constructor\n"; } }; class X : public D1, virtual public D2 { public: X() { cout << "In X constructor\n"; } }; int main() { X x; return 0; } 

Program Output:

 In B1 constructor In V1 constructor In B1 constructor In B2 constructor In V2 constructor In B3 constructor In D2 constructor In D1 constructor In X constructor 

I expected this conclusion:

 In B1 constructor In B2 constructor In V2 constructor In B2 constructor In D2 constructor In B1 constructor In V1 constructor In D1 constructor In X constructor 

based on the fact that first an object of the virtual base class is created, and then another object of the base class. Can someone explain this behavior?

+1
source share
2 answers

The exact quote from the standard is 12.6.2p10:

In the constructor without delegation, initialization is performed in the following order:

- Firstly, and only for the constructor of the derived class itself (1.8), the virtual base classes are initialized in the order in which they appear at the first intersection from left to right from left to right of the acyclic graph base classes , where from left to right is the order in which the base classes appear classes in the base specifier-list of the derived class.

- Then direct base classes are initialized in the order of declaration, as they appear in the list of base qualifiers (regardless of the order of mem initializers).

- Then non-static data elements are initialized in the order in which they were declared in the class definition (again, regardless of the order of mem-initializers).

- Finally, the compound instruction of the constructor body is executed.

I believe the key is depth, first from left to right in a half-dead text. The class V1 is the virtual base X , which is to the left of V2 , even if it is deeper in the hierarchy.

The hierarchy chart in your case looks like this:

  X / \\ D1 D2 || / \\ V1 B3 V2 | / \ B1 B1* B2 

In cases where single lines define ordinary inheritance, and double lines define virtual inheritance. Note that in your full object X there are two instances of B1 . Now, if you perform a search in depth left-right, you will walk through the nodes in the following order:

 [ B1, V1, D1, B3, B1*, B2, V2, D2, X ] 

And the virtual bases V1 , V2 , D2 , which are the order of their construction. V1 requires construction B1 . V2 requires the construction of B1* and B2 , D2 requires B3 , so the order should be:

 [ B1, V1, B1*, B2, V2, B3, D2, D1, X ] 

Where B1 build starts with V1 , B1* and B2 must be ordered before V2 , B3 starts as a dependency on D2 . At this stage, all virtual databases are created and non-virtual databases begin to be built. The only non-virtual base X that was not initialized due to the dependencies of the virtual databases is D1 .

If the diamond was closed (say that V1 and V2 inherited practically from B1 , then there will be only one instance of B1 , and it will be the first subobject to be built.

+3
source

C ++ always first creates the first or most base class. Then it goes through the inheritance tree in order and builds each subsequent derived class.

0
source

Source: https://habr.com/ru/post/918899/


All Articles