调用构造函数的命令

时间:2014-01-10 00:09:24

标签: c++ inheritance constructor multiple-inheritance

#include <iostream>
using namespace std;    
struct A{
  A() {cout << "A" << endl;}
  A(int a) {cout << "A+" << endl;}
};

struct B : virtual A{
  B() : A(1) {cout << "B" << endl;}
};
struct C : virtual A{
  C() : A(1) {cout << "C" << endl;}
};
struct D : virtual A{
  D() : A() {cout << "D" << endl;}
};
struct E : B, virtual C, D{
  E(){cout << "E" << endl;}
};
struct F : D, virtual C{
  F(){cout << "F" << endl;}
};
struct G : E, F{
  G() {cout << "G" << endl;}
};

int main(){
  G g;
  return 0;
}

节目打印:

A
C
B
D
E
D
F
G

我想知道应该使用哪些规则来确定构造函数被调用的顺序。感谢。

3 个答案:

答案 0 :(得分:1)

您应该遵循C ++标准中给出的规则:

  

[C++11: 12.6.2/10]:在非委托构造函数中,初始化按以下顺序进行:

     
      
  • 首先,仅对于派生程度最高的类(1.8)的构造函数,虚拟基类按照它们出现在基本有向无环图的深度优先从左到右遍历的顺序进行初始化类,其中“从左到右”是派生类 base-specifier-list 中基类的出现顺序。
  •   
  • 然后,直接基类按声明顺序初始化,因为它们出现在base-specifier-list中(无论 mem-initializers 的顺序如何)。 < / LI>   
  • 然后,非静态数据成员按照在类定义中声明的顺序进行初始化(同样,无论 mem-initializers 的顺序如何)。
  •   
  • 最后,执行构造函数体的复合语句
  •   
     

[注意:声明命令的目的是确保以与初始化相反的顺序销毁基础和成员子对象。 -end note]

答案 1 :(得分:1)

虚拟基础子对象首先由最派生的类构建,然后在任何其他基础之前构建。这是唯一有意义的方法,因为在运行时(因此“虚拟”),对象构造之前,不知道虚拟基础与最大派生对象的关系。虚拟碱基的所有中间初始化程序都将被忽略。

那么,你的虚拟基地是什么? G来自EFE几乎从C派生,而A实际上是从A派生的,因此CF是第一位的。接下来,E不会添加任何进一步的虚拟基础。接下来,B按顺序具有非虚拟基础DE,接下来构建,然后F完成。然后是D的非虚拟基础FG已完成。最后,A已完成。

总而言之,它是虚拟基地CB,然后是非虚拟基地DEDFG,然后是{{1}}本身。

答案 2 :(得分:0)

您可以从C ++标准的引用中调查构造函数调用的顺序,并尝试自己捕获它

  

10在非委托构造函数中,初始化继续进行   以下顺序: - 首先,仅适用于最多的构造函数   派生类(1.8),虚拟基类按顺序初始化   它们出现在深度优先的从左到右的遍历中   基类的非循环图,其中“从左到右”是基数的顺序   派生类中基类的外观   基本符列表。 - 然后,直接基类被初始化   声明顺序,因为它们出现在base-specifier-list中   (不管mem-initializers的顺序如何)。 - 然后,非静态   数据成员按照在其中声明的顺序进行初始化   类定义(再次无论顺序如何   MEM-初始化)。 - 最后,复合声明   构造函数体被执行。 [注意:声明顺序是   强制要求确保基地和成员子对象被销毁   初始化的逆序。 - 后注]