基类初始化器和成员变量初始化器的顺序是否重要?

时间:2012-01-13 17:03:33

标签: c++ constructor initialization

类'构造函数的初始值设定项的顺序是否显着?

所以说我有:

class MyClass : BaseClass
{
      int a, b, c;

   public:
      MyClass(int);
}

e.g。 1:

MyClass::MyClass(int forBase) :
  a(7),
  b(14),
  c(28),
  BaseClass(forBase) { }

e.g。 2:

MyClass::MyClass(int forBase) :
  BaseClass(forBase),
  a(7),
  b(14),
  c(28) { }

示例1会做一些与示例2不同的事情吗?

3 个答案:

答案 0 :(得分:8)

  

示例1会做一些与示例2不同的事情吗?

即可。初始化顺序由标准决定,而不是由您编写初始化程序的顺序决定:

  

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

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

事实上,如果你以任何其他顺序编写它们而一个依赖于另一个,you may well be warned about it

struct T {
   std::vector<int> v;
   int w;

   T(int w) : w(w), v(0, w) {}
};

int main() {
   T t(3);
}

// g++ 4.1.2:
// t.cpp: In constructor 'T::T(int)':
// Line 3: warning: 'T::w' will be initialized after
// Line 2: warning:   '__gnu_debug_def::vector<int, std::allocator<int> > T::v'
// Line 5: warning:   when initialized here

答案 1 :(得分:4)

顺序对于编译器无关紧要(初始化顺序始终是基类,并且始终按照派生的顺序排列基类,并且按声明的顺序排列成员),但它对读者来说很重要:它是如果您为初始化程序提供的顺序与它们的执行顺序不匹配,则会非常混乱。虽然在大多数情况下并不重要,但在某些情况下,您可以创建微妙的错误,例如

struct Derived: Base
{
  int member;
  Derived();
}

Derived::Derived():
  member(3),
  Base(member) // This is executed *before* member is initialized!
{
}

如果按照正确的顺序给出初始值设定项,那么这个bug会更清楚地突出显示:

Derived::Derived():
  Base(member), // Now we see immediately that member is uninitialized
  member(3),
{
}

答案 2 :(得分:4)

在构造函数初始化列表中列出初始值设定项的顺序无关紧要。成员按照声明的顺序进行初始化,并在成员之前初始化基础。

但是,如果子对象的初始值取决于其他子对象的值,则以不同的顺序列出初始值设定项,这可能会咬你。

class A
{
  int y, x;
  A(int x_value): x(x_value), y(x) {}
};

由于y在x之前初始化,因此它获得了一个垃圾值,初始化列表的顺序只是隐藏了这个bug。这就是为什么这值得编译警告。