使用虚拟继承时调用默认构造函数

Default constructor getting called while using virtual inheritance

本文关键字:调用 默认 构造函数 继承 虚拟      更新时间:2023-10-16

在下面的代码中,当我创建 C 的对象时,A'a 默认构造函数通过 B 的构造函数被调用,为什么会这样?

#include <iostream>
using namespace std;
class A
{
public:
    int a;
    A(int z): a(z) {cout<<"a is "<<a;}
    A() { cout<<" it came heren";}
};
class B: public virtual A
{
public:
    B(int z): A(z) {cout<<"in B and z is "<<z<<"n"; }
};
class C:public B
{
public:
    C(int z): B(z) {cout<<" In Cn"; }
};
int main()
{
    C b(6);
    cout<<b.a;
    return 0;
}

这就是标准中描述虚拟继承的方式。

[12.6.2] — 首先,并且仅对于派生最多的类 (1.8( 的构造函数,虚拟基类按照它们在基类的有向无环图的深度优先从左到右遍历上的顺序进行初始化,其中"从左到右"是基类在派生类基说明符列表中的出现顺序。

特别是,在构造C时,A子对象先于其他任何对象(包括B子对象(进行初始化。由于A不在违规C构造函数的mem-initializers列表中,因此使用 A 的默认构造函数。

[12.6.2] — 然后,直接基类按照它们出现在基说明符列表中的声明顺序进行初始化(无论 mem 初始值设定项的顺序如何(。

然后构造B子对象。

[12.6.2] 一个 mem 初始值设定项,其中 mem-initializer-id 表示虚拟基类,在执行不是派生最多的类的任何类的构造函数时被忽略。

构造

B 的构造函数中的: A(z)在构造 CB子对象时被忽略。

在日常语言中,这意味着您必须在每个直接或间接派生类中初始化一个虚拟基类,就好像它是直接派生类一样。如果您忘记这样做,将强制使用默认构造函数,并可能带来毁灭性的后果。(这就是为什么您应该努力在任何虚拟基类中使用默认构造函数或根本没有默认构造函数的原因(。