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

Does the order of base-class initializers and member variable initializers matter?

本文关键字:初始化 顺序 变量 成员 基类      更新时间:2023-10-16

类构造函数的初始值设定项的顺序是否重要?

所以说我有:

class MyClass : BaseClass
{
      int a, b, c;
   public:
      MyClass(int);
}

例如1:

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

例如2:

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

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

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

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

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

  • 首先,并且仅对于最派生类(1.8)的构造函数,虚拟基类按照它们在基类的有向无环图的深度优先从左到右遍历中出现的顺序进行初始化,其中"从左到左"是基类在派生类基类说明符列表中的出现顺序
  • 然后,直接基类按照它们在基说明符列表中出现的声明顺序进行初始化(无论mem初始化器的顺序如何)
  • 然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样,与mem初始化程序的顺序无关)
  • 最后,执行构造函数主体的复合语句

事实上,如果你以任何其他顺序写它们,并且其中一个依赖于另一个,你很可能会被警告:

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

顺序对编译器来说并不重要(初始化顺序始终是基类优先,基类按派生顺序,成员按声明顺序),但对读者来说很重要:如果初始化程序的执行顺序与它们的执行顺序不匹配,那将非常令人困惑。虽然在大多数情况下这并不重要,但在某些情况下,你可以创建微妙的错误,例如

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

如果初始化程序的顺序正确,这个错误会更加突出:

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

在构造函数初始化列表中按哪个顺序列出初始化项并不重要。成员按照声明的顺序进行初始化,基在成员之前进行初始化。

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

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

由于y是在x之前初始化的,所以它会得到一个垃圾值,初始化器列表的顺序只会隐藏错误。这就是为什么这值得编译器警告的原因。