你好, 如您所见,示例中的构建顺序是:– U1 U2 Y X V2 V1 V3 V4 B1 B2 D
我理解:U1 U2 Y X 被初始化,因为 V2 是对 D 的第一个直接虚拟继承,为了初始化它,需要初始化这些首先 U1 U2 Y X 。在那之后V2 被初始化了,但是为什么V1 在V3 之前被初始化,尽管从V3 有直接的虚拟继承。
请忽略节点和箭头的数字,注意红色箭头为非虚拟继承,黑色箭头为虚拟。
注意:原始文件可以找到there .
最佳答案
这是我对这个例子的理解。它符合施工顺序,所以我相信它是正确的。但是,我不确定。
首先,箭头的数字很重要,因为它们告诉您定义基类的顺序。以D
为例,类定义如下:
class D : virtual V2, B1, B2, virtual v3 {...}
鉴于此,我的下一步是遍历图并将所有类放入深度优先顺序,无论它们是否为虚拟。大括号表示基类。括号表示已经在我的类列表中的虚拟基类:
D {V2 {X {U1, U2}, Y {(U2), (U1)}}, B1 {V1, (V2), V3 {(Y), (U2)}, V4}, B2 {(V4-V1)}, (V3)
对我来说,这是
- 要构造 D,首先我需要 V2。
- V2 需要 X,X 需要 U1 和 U2。
- 下一个 V2 需要 Y,Y 需要 U2 和 U1,但两者都已经在我的列表中。
- 下一个 D 需要 B1。
- B1 需要 V1、V2、V3 和 V4,V2 已经在我的列表中。
- V3 需要 Y 和 U2,但两者都已在我的列表中。
- 下一个 D 需要 B2,它需要 V4 到 V1,所有这些都在我的列表中。
- 最后,D 需要 V3,但同样,它已经在我的列表中。
鉴于此,我现在将删除多余的基类,留下:
D {V2 {X {U1, U2}, Y}, B1 {V1, V3, V4}, B2}
下一部分是找到非虚拟基类并对我的列表进行调整。
- V2 需要 X 和 Y,其中 Y 是虚拟的,因此 Y 必须在 X 之前。
关于此的额外要点:鉴于您的问题,我希望您也认为 U2 应该在 U1 之前,因为 Y 在 X 之前构造,并且在 Y 中,U2 首先导出。但是,这不会发生。相反,X 的虚拟基类是按顺序完成的,然后是 Y,最后是 X。
这会将我的列表调整为以下内容:
D {V2 { {U1, U2}, Y, X}, B1 {V1, V3, V4}, B2}
最后,B1是非虚拟的,所以需要在V1、V3、V4之后。这留下了:
D {V2 { {U1, U2}, Y, X}, {V1, V3, V4}, B1, B2}
请注意,B2 也是非虚拟的,如果它不在我的列表中,则需要考虑。
这给了我一个令我满意的订单。唯一的问题是我将派生类列在基类之前,我们知道基类是先构造的。这是一个问题的唯一两个地方是
- D,需要放在最后。
- V2,需要在其子项之后。
所以我将调整我的列表以将这两项移动,V2 移到 X 之后,D 移到 B2 之后。
{ { {U1, U2}, Y, X} V2, {V1, V3, V4}, B1, B2} D
现在我将删除括号并:
U1, U2, Y, X, V2, V1, V3, V4, B1, B2, D
您可以看到这与图表中构造函数的顺序相匹配,并且实际上与我使用 Visual Studio 2012 构建时调用的顺序相匹配。
关于C++虚继承初始化顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15885601/