在下面的代码中,当我创建C的对象时,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 here\n";}
};
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 C\n"; }
};
int main()
{
C b(6);
cout<<b.a;
return 0;
}
答案 0 :(得分:0)
这就是标准中描述虚拟继承的方式。
[12.6.2] - 首先,仅对于派生程度最高的类(1.8)的构造函数,虚拟基类按照它们在有向无环的深度优先从左到右遍历时出现的顺序进行初始化基类的图形,其中“从左到右”是派生类 base-specifier-list 中基类的出现顺序。
特别是,在构建C
时,A
子对象会先于其他任何对象(包括B
子对象)进行初始化。由于A
不在违规mem-initializers
构造函数的C
列表中,因此使用A
的默认构造函数。
[12.6.2] - 然后,直接基类按声明顺序初始化,因为它们出现在base-specifier-list中(无论 mem-initializers 的顺序如何)。
然后构建B
子对象。
构建[12.6.2] mem-initializer ,其中 mem-initializer-id 表示虚拟基类在执行任何类的构造函数时被忽略不是派生最多的阶级。
: A(z)
的{{1}}子对象时,B
的构造函数中的 B
将被忽略。
在日常语言中,这意味着您必须在每个直接或间接派生类中初始化虚拟基类,就好像它是直接派生类一样。如果您忘记这样做,将强制使用默认构造函数,这可能会带来毁灭性后果。 (这就是为什么你应该努力在任何虚拟基类中都仅默认构造函数或 no 默认构造函数)。