Behaviour of virtual inheritance in this case

匆匆过客 提交于 2019-12-05 07:26:17

问题


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;
}

Output of the program:

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 an output like this:

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

on the basis that an object of a virtual base class is constructed first and then the other base class object. Can Someone explain this behaviour?


回答1:


The exact quote from the standard is 12.6.2p10:

In a non-delegating constructor, initialization proceeds in the following order:

— First, and only for the constructor of the most derived class (1.8), 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.

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

The hierarchy graph in your case is like:

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

Where single lines identify plain inheritance, and double lines are virtual inheritance. Note that there are two instances of B1 in your complete object X. Now if you perform a depth-first left-to-right search you will walk the nodes in the following order:

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

And the virtual bases are V1, V2, D2, which is the order in which they will be constructed. V1 requires the construction of 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 construction is triggered by V1, B1* and B2 must be ordered before V2, B3 is triggered as a dependency of D2. At this point all of the virtual bases are built and the non-virtual bases start to be constructed. The only non-virtual base of X that has not been initialized due to the dependencies of the virtual bases is D1.

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




回答2:


C++ always constructs the “first” or “most base” class first. It then walks through the inheritance tree in order and constructs each successive derived class.



来源:https://stackoverflow.com/questions/10304300/behaviour-of-virtual-inheritance-in-this-case

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!