c ++虚拟继承初始化顺序

时间:2013-04-08 17:49:15

标签: c++ virtual multiple-inheritance

您好, 如您所见,示例中的构造顺序为: - U1 U2 Y X V2 V1 V3 V4 B1 B2 D

我理解: U1 U2 YX 已初始化,因为 V2 是D的第一个直接虚拟继承,为了初始化它需要初始化这些首先 U1 U2 YX 。之后 V2 被初始化,但为什么 V1 V3 之前被初始化,尽管有 V3 的直接虚拟继承。

请忽略节点和箭头的编号,注意红色箭头是非虚拟继承,黑色箭头是虚拟的。

注意:可能会找到原始文档there

2 个答案:

答案 0 :(得分:3)

以下是我对该示例的理解。它符合施工顺序,所以我认为这是正确的。但是,我不确定。

首先,箭头的数量很重要,因为它们会告诉您基类定义的顺序。仅以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,需要U1和U2。
  • 下一个V2需要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,需要在孩子之后。

所以我会调整我的列表来移动这两个项目,在X之后是V2,在B2之后是D.

{ { {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构建时调用的顺序相匹配。

答案 1 :(得分:0)

我只会解答有关V1和V3顺序的问题。

第一步是:

  

深度优先左右扫描中应用拓扑排序排名继承DAG,

     
      
  • 虚拟和非虚拟继承一样
  •   

根据这个规则,V1在V3之前出现:V1更深,而在V3的左边,无论继承类型如何。从左到右的顺序由从D到相关节点的连续祖先的直接继承等级定义。该等级由图的节点之间的边缘承载(因此不能被忽略):V3具有等级(3),而V2具有等级(1) - 并且还有(2,2)被较高的一个取消 - 并且V1具有等级(2,1)。因此,顺序是V2,然后是这三个节点之间的V1,然后是V3。

注意:为了清晰起见,图表没有以正确的左右顺序描述节点,假设V2和V3与其他节点保持关系的数量,而V1没有任何祖先。

第2步是:

  

构建所有虚拟基类(立即和非立即)

     
      
  • 使用排名顺序
  •   
  • 不构造两次
  •   
     

[...]

V1和V3几乎都是继承的,V1代表B1,V3代表D,所以它们都是按照步骤1中建立的顺序在此步骤构建的。