嗨,正如您在示例中看到的构造顺序是: – U1 U2 YX V2 V1 V3 V4 B1 B2 D
我的理解是:U1 U2 YX被初始化是因为V2是第一个直接虚拟继承到 D 的,为了初始化它需要初始化这些U1 U2 YX。在那之后V2被初始化,但是为什么V1在V3之前被初始化,虽然从V3有直接的虚拟继承。
请忽略节点和箭头的数量,注意红色箭头是非虚拟继承,黑色箭头是虚拟的。
注意:原始文件可以在那里找到。
嗨,正如您在示例中看到的构造顺序是: – U1 U2 YX V2 V1 V3 V4 B1 B2 D
我的理解是:U1 U2 YX被初始化是因为V2是第一个直接虚拟继承到 D 的,为了初始化它需要初始化这些U1 U2 YX。在那之后V2被初始化,但是为什么V1在V3之前被初始化,虽然从V3有直接的虚拟继承。
请忽略节点和箭头的数量,注意红色箭头是非虚拟继承,黑色箭头是虚拟的。
注意:原始文件可以在那里找到。
这是我对这个例子的理解。它符合施工顺序,所以我相信它是正确的。但是,我不确定。
首先,箭头的数字很重要,因为它们告诉您定义基类的顺序。仅用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 {X {U1, U2}, Y}, B1 {V1, V3, V4}, B2}
下一部分是找到非虚拟基类并对我的列表进行调整。
关于这一点的额外一点:鉴于您的问题,我希望您也认为 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 也是非虚拟的,如果它不在我的列表中,则需要考虑它。
这给了我一个令我满意的订单。唯一的问题是我在基类之前列出了派生类,我们知道基类是首先构造的。剩下的唯一两个有问题的地方是
所以我将调整我的列表以移动这两个项目,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 构建时调用的顺序相匹配。
我只会解决您关于 V1 和 V3 顺序的问题。
第一步是:
在深度优先、左右扫描中应用拓扑排序排序继承 DAG ,
- 虚拟和非虚拟继承被同等对待。
根据这条规则,V1 在 V3 之前:V1 更深,在 V3 的左侧,无论继承类型如何。从左到右的顺序由从 D 到相关节点的连续祖先的直接继承等级定义。该等级由图节点之间的边承载(因此不能忽略):V3 具有等级 (3),而 V2 具有等级 (1) - 并且 (2,2) 被较高的取消 - V1 的秩为 (2, 1)。因此,这 3 个节点之间的顺序是 V2,然后是 V1,然后是 V3。
注意:考虑到 V2 和 V3 与其他节点保持的关系数量,该图没有以正确的左右顺序描述节点,而 V1 没有任何祖先。
第2步是:
构造所有虚拟基类(立即和非立即)
- 使用排名顺序。
- 不要构造两次
[...]
V1 和 V3 都是虚拟继承的,V1 用于 B1,V3 用于 D,因此它们都在此步骤中按照步骤 1 中确定的顺序构建。