构造函数调用命令与组成

时间:2013-06-01 13:26:12

标签: c++ inheritance constructor composition

我有A级和B级。 C类派生自B类,并具有A类对象作为组合。 http://ideone.com/JGT48M

#include "iostream"
using namespace std;

class A {
  int i;
public:
  A(int ii) : i(ii) {
      cout << "\n Constructor of A is called \n";

  }
  ~A() {
      cout << "\n destructor  of A is called \n";
  }
  void f() const {}
};

class B {
  int i;
public:
  B(int ii) : i(ii) {
      cout << "\n Constructor of B is called \n";
  }
  ~B() {
      cout << "\n destructor  of B is called \n";
  }
  void f() const {}
};

class C : public B {
  A a;
public:
  C(int ii) : a(ii), B(ii) {
      cout << "\n Constructor of C is called \n";
  }
  ~C() {
  cout << "\n destructor  of C is called \n";
  } // Calls ~A() and ~B()
  void f() const {  // Redefinition
    a.f();
    B::f();
  }
};

int main() {
  C c(47);
} ///:~

我已经读过根据在派生类构造函数中调用它们的方式来调用构造函数。我的意思是让一个名为REF的类派生自REF_BASE1和REF_BASE2然后

 REF (int ii) : REF_BASE2(ii), REF_BASE1 (ii) {

意味着首先调用REF_BASE2然后调用REF_BASE1然后调用REF构造函数。 如果我们将其定义为

REF (int ii) : REF_BASE1(ii), REF_BASE2 (ii) {

意味着首先调用REF_BASE1然后调用REF_BASE2然后调用REF构造函数。

然而,在我上面的程序中,我明确地&#34;错误地&#34;声明通过内部组合变量A a首先被初始化然后B应该被初始化,但是编译器以正确的方式做了但是没有让我知道我的错误

以上程序的输出与我在派生类constcutor初始化列表中指定的顺序无关

Constructor of B is called 

 Constructor of A is called 

 Constructor of C is called 

 destructor  of C is called 

 destructor  of A is called 

 destructor  of B is called 

我的问题是 1)编译器为什么不抱怨?或者我是对的吗? 2)派生构造函数中的顺序是否严格遵循?

1 个答案:

答案 0 :(得分:4)

我将从第二个问题开始:

  

2)是派生构造函数中的顺序没有严格遵循?

顺序不是出现在构造函数初始化列表中的顺序,而是基类出现在类定义中的顺序。

因此,如果您的类定义如下所示:

struct A : B, C
{
    // ...
};

然后B的构造函数将在C的构造函数之前被调用,无论你在A的构造函数的初始化列表中指定了什么顺序。

C ++ 11标准的第12.6.2 / 10段规定:

  

在非委托构造函数中,初始化按以下顺序进行:

     

- 首先,只有最派生类(1.8)的构造函数,才初始化虚拟基类   它们出现在基类的有向无环图的深度优先从左到右遍历中的顺序,   其中“从左到右”是派生类base-specifier-list中基类出现的顺序。

     

- 然后,直接基类按声明顺序初始化,因为它们出现在base-specifier-list中   (无论mem-initializers的顺序如何)

     

- 然后,按照在类定义中声明的顺序初始化非静态数据成员   (再次不管mem-initializers的顺序如何)。

     

- 最后,执行构造函数体的复合语句。

现在第一个问题:

  

1)编译器为什么不抱怨?

编译器可能会警告您构造函数初始化列表中的初始化顺序与基类列表中的初始化顺序不同(GCC与-Wall相同),但不必。最终,只有后者很重要。