如果我有类继承关系,如下所示
a
/ \
b c
\ |
| d
\/ \
e f
\ /
g
以下是正确的定义吗?
class A {};
class B: public virtual A {};
class C: public virtual A {};
class D: public C {};
class E: public B, public virtual D {};
class F: public virtual D {};
class G: public E, public F {};
我让A和D几乎都是遗传的,因为我认为每个联合课都需要是虚拟的。
此外,我不确定C ++如何定义上述情况的构造函数顺序。链接 https://isocpp.org/wiki/faq/multiple-inheritance#mi-vi-ctor-order说
要执行的第一个构造函数是虚拟基础 层次结构中的任何类。它们按照它们的顺序执行 出现在基础图的深度优先从左到右的遍历中 类,从左到右指的是基数的出现顺序 班级名称。
完成所有虚拟基类构造函数之后 构造顺序通常是从基类到派生类。该 如果您想象第一个,那么细节最容易理解 编译器在派生类的ctor中做的事情就是创建一个 隐藏调用其非虚拟基类的ctors(提示:那是 许多编译器实际执行的方式)。所以,如果D类继承 从B1和B2相乘,B1的构造函数先执行,然后执行 B2的构造函数,然后是D的构造函数。这个规则是 递归地应用;例如,如果B1继承自B1a和B1b,和 B2继承自B2a和B2b,最后的顺序是B1a,B1b,B1, B2a,B2b,B2,D。
请注意,顺序B1和B2(或B1a然后B1b)由下式确定 基类出现在声明中的顺序 class,而不是初始化程序在派生中出现的顺序 class的初始化列表。
如果是,那顺序是什么?
A, D, B, C, D, F, G
我不认为D是在C之前构造的。什么是正确的构造函数顺序?
答案 0 :(得分:9)
构造类A
的对象时,首先初始化虚拟基类。这导致调用D
和D
的构造函数。 C
的构造函数将构造它的基础G
对象。然后将调用E
的非基类的构造函数,即F
和E
。 B
的构造函数将调用A C D B E F G
的构造函数。这给出了最终的顺序:
{{1}}
答案 1 :(得分:6)
我添加了调用printf
的构造函数来观察发生了什么(Godbolt上的代码可用于好奇)。我得到的订单,包括clang(版本6.0.0)和gcc(版本6.4.0和7.3.0),是:
A
C
D
B
E
F
G
这符合我的期望。必须首先构造A
和D
,但是如果没有C,则无法构造D
(想象一下D
的构造函数调用{C
的更复杂的示例{1}}。一旦满足所有virtual
继承,就会按照我们期望的顺序调用构造函数。