可以使用成员变量初始化初始化列表中的其他成员吗?

Pon*_*don 30 c++ initialization-list member-variables

考虑以下(简化)情况:

class Foo
{
private:
    int evenA;
    int evenB;
    int evenSum;
public:
    Foo(int a, int b) : evenA(a-(a%2)), evenB(b-(b%2)), evenSum(evenA+evenB)
    {
    }
};
Run Code Online (Sandbox Code Playgroud)

当我像这样实现Foo时:

Foo foo(1,3);
Run Code Online (Sandbox Code Playgroud)

然后evenA是0,evenB是2,但是甚至将初始化为2?

我在我当前的平台(iOS)上尝试了这个,它似乎工作,但我不确定这段代码是否可移植.

谢谢你的帮助!

Oli*_*rth 32

明确定义和可移植的,1但它可能容易出错.

成员按照它们在类主体中声明的顺序进行初始化,而不是它们在初始化列表中列出的顺序.因此,如果您更改类主体,此代码可能会无声地失败(尽管许多编译器会发现它并发出警告).


1.来自C++标准中的[class.base.init]:

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

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

(突出显示是我的.)

然后,标准的这一部分继续给出使用成员变量初始化其他成员变量的示例.


Jam*_*nze 8

是的,只要他们已经建成了.只是不要忘记构造的顺序是类定义中声明的顺序,而不是构造函数中初始化器的顺序.并且编译器通常不会告诉您是否在构造之前使用变量.在你的情况下,例如,如果你移动evenSum到类的顶部,你有未定义的行为(因为它的初始化程序使用未初始化的成员),即使在你的构造函数中,你在之前初始化evenAevenB词法evenSum.


Ale*_*lin 6

成员按照在类定义中声明的顺序进行初始化.只要您的初始化程序列表遵循此顺序,它就应该没问题.