2

我有 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_BASE1 和 REF_BASE2 派生的名为 REF 的类

 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 构造函数。

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

无论我在派生类构造函数初始化列表中指定的顺序如何,上述程序的输出是

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) 派生构造函数中的顺序是否没有严格遵循?

4

1 回答 1

5

我将从第二个问题开始:

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

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

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

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

那么无论你在 ' 的构造函数的初始化列表中指定什么顺序,B都会在 的构造函数之前调用 的构造函数。CA

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

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

— 首先,并且仅对于最派生类 (1.8) 的构造函数,虚拟基类按照它们在基类的有向无环图的深度优先从左到右遍历中出现的顺序进行初始化,其中“左-to-right”是派生类基类说明符列表中基类的出现顺序。

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

— 然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样不管 mem-initializers 的顺序)。

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

现在第一个问题:

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

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

于 2013-06-01T13:29:28.680 回答