MKo*_*MKo 23 c++ compiler-construction inheritance virtual-inheritance
编译器如何实现虚拟继承?
在以下代码中:
class A {
public:
A(int) {}
};
class B : public virtual A {
public:
B() : A(1) {}
};
class C : public B {
public:
C() : A(3), B() {}
};
Run Code Online (Sandbox Code Playgroud)
编译器是否生成两个B::ctor函数实例,一个没有A(1)调用,一个带有它?因此,当B::constructor从派生类的构造函数调用时,将使用第一个实例,否则使用第二个实例.
编译器不会创建另一个B的构造函数 - 但它忽略了A(1).由于A实际上是继承的,因此首先使用其默认构造函数构造它.并且由于它在B()调用时已经构造,因此A(1)忽略该部分.
编辑-我错过了A(3)部分C的构造初始化列表.使用虚拟继承时,只有最派生的类初始化虚拟基类.因此A将使用A(3)而不是其默认构造函数构造.其余的仍然存在 - A中间类(此处B)的任何初始化都将被忽略.
编辑2,试图回答有关上述实施的实际问题:
在Visual Studio中(至少2010年),使用标志而不是具有两个实现B().由于在调用构造函数之前B实际上继承了该标志,因此检查了该标志.如果未设置标志,则跳过调用.然后,在每个派生的类中,标志在初始化之后被重置.同样的机制是用来防止从初始化,如果它的某些部分(如果从继承, 将初始化).AAA()BACADDCDA
它依赖于实现.例如,GCC(请参阅此问题)将发出两个构造函数,一个调用A(1),另一个调用.
B1()
B2() // no A
Run Code Online (Sandbox Code Playgroud)
构造B时,调用"完整"版本:
B1():
A(1)
B() body
Run Code Online (Sandbox Code Playgroud)
构造C时,将调用基本版本:
C():
A(3)
B2()
B() body
C() body
Run Code Online (Sandbox Code Playgroud)
事实上,即使没有虚拟继承,也会发出两个构造函数,它们将是相同的.