【问题标题】:How direct base is constructed in virtual inheritance?虚拟继承中如何构造直接基数?
【发布时间】:2016-08-07 12:01:44
【问题描述】:

在下面的代码中,我试图创建一个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

我知道objBase1是虚拟继承的,但是在obj的构造过程中,还需要构造Level2Level1,这导致Base1在它们的每一个结构体。但是整个构造过程只调用了一次Base1构造函数。我无法解释这一点。这是否意味着Level2 中的Base1obj 内部的Level1 与直接属于Base1Base1 共享相同的数据?

【问题讨论】:

  • 虚拟继承的全部意义在于你只有一个虚拟基础子对象。
  • 您知道,与 C 不同,C++ 中的空参数列表就是 (),对吧?

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


【解决方案1】:

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

解释是Base1 是层次结构中所有类的虚拟基础。这正是虚拟基的含义和用途:共享通用基类实例。

来自cppreference的报价

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

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

考虑到虚拟继承,你的结构图可以这样认为:

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

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

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

【讨论】:

    【解决方案2】:

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

    是的,Base1 只有一个子对象,并由类Leaf 中的Level2Level1 的基本子对象共享。

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

    再举个例子,

    class V { /* ... */ };
    class A : virtual public V { /* ... */ };
    class B : virtual public V { /* ... */ };
    class C : public A, public B { /* ... */ };
    

    对于C 类类型的对象cV 类型的单个子对象是 c 的每个基子对象共享,其虚拟基类为 输入V。给定上面定义的类C,类C的对象将 有一个V 类的一个子对象,如下所示。

    【讨论】:

      猜你喜欢
      • 2013-10-24
      • 1970-01-01
      • 2015-06-21
      • 1970-01-01
      • 1970-01-01
      • 2018-04-18
      • 2021-06-02
      • 1970-01-01
      相关资源
      最近更新 更多