如何在虚拟继承中构造直接基础?

时间:2016-04-15 13:23:24

标签: c++ inheritance multiple-inheritance virtual-inheritance

在下面的代码中,我尝试创建一个Leaf对象obj来查看多层继承中的构造函数顺序,但我发现obj的结构和构造函数调用这个案子有点奇怪。

#include<iostream>
using namespace std;
class Base1 { 
public:
    Base1(void) { 
        cout << "class Base1" << endl; 
    } 
}; 
class Base2 {
public: 
    Base2(void) { 
        cout << "class Base2" << endl; }
};
class Level1 : public Base2, virtual public Base1
{
public:
    Level1(void)
    {
        cout << "class Level1" << endl;
    }
};

class Level2 : public Base2, virtual public Base1
{
public:
    Level2(void)
    {
        cout << "class Level2" << endl;
    }
};

class Leaf :virtual public Level2, virtual public Level1
{
public:
    Leaf(void)
    {
        cout << "class Leaf" << endl;
    }
};


int main(void)
{
    Leaf obj;
    return 0;
}

输出显示构造函数调用:

class Base1
class Base2
clase Level2
class Base2
class Level1
class Leaf

但是程序结尾的obj结构实际上是:

obj
--Level2
----Base2
----Base1
--Level1
----Base2
----Base1
--Base1

我知道Base1的{​​{1}}是虚拟继承的,但在构建obj期间,还需要构建objLevel2,在每个结构中都会导致Level1。但整个构建过程只调用Base1构造函数一次。我无法解释这一点。这是否意味着Base1中的Base1Level2内的Level1与直接属于obj的{​​{1}}共享相同的数据?

2 个答案:

答案 0 :(得分:4)

  

但整个构建过程只调用一次Base1构造函数。我无法解释这一点。

解释是Base1是层次结构中所有类的虚拟基础。这正是虚拟基础及其用途:共享公共基类实例。

来自cppreference

的报价
  

对于指定为virtual的每个不同的基类,最派生的对象只包含该类型的一个基类子对象,即使该类在继承层次结构中多次出现(只要它每次都是虚拟继承)。

     

所有虚拟基础子对象在任何非虚拟基础子对象之前初始化,因此只有最派生的类在其成员初始化列表中调用虚拟基础的构造函数:

考虑虚拟继承,您的结构图可以被认为是这样的:

obj
--Level2
----Base2
----+-------Base1
--Level1   / /
----Base2 / /
----+----/ /
--+-------/
  

这是否意味着Level2中的Base1和obj中的Level1与直接属于obj的Base1共享相同的数据?

是。 Base1的整个结构中只有一个obj个实例。

答案 1 :(得分:1)

  

这是否意味着Level2中的Base1和obj中的Level1与直接属于obj的Base1共享相同的数据?

是的,Base1只有一个子对象,并且由Level2的{​​{1}}和Level1的基础子对象共享。

以下是标准的示例解释,$ 10.1 / 6多个基类[class.mi](强调我的)

  

另一个例子,

Leaf
     

对于类类型class V { /* ... */ }; class A : virtual public V { /* ... */ }; class B : virtual public V { /* ... */ }; class C : public A, public B { /* ... */ }; 的对象c,类型C的单个子对象是   由具有虚拟基类的V 的每个基础子对象共享   输入c。鉴于上面定义的类V,类C的对象将会   有一个<{1}}的子对象,如下所示。