39

考虑以下(简化的)情况:

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)
    {
    }
};

当我像这样实例化 Foo 时:

Foo foo(1,3);

那么evenA为0,evenB为2,但是evenSum会被初始化为2吗?

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

谢谢你的帮助!

4

4 回答 4

42

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

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


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

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

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

(突出显示是我的。)

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

于 2012-05-23T12:57:48.443 回答
10

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

于 2012-05-23T13:00:11.977 回答
8

成员按照它们在类定义中声明的顺序进行初始化。只要您的初始化程序列表遵循此顺序,就可以了。

于 2012-05-23T12:57:22.517 回答
-2

这也在 g++ 4.0.3(现在 6 岁)上编译没有错误。

我相信这将在任何合理的最新编译器上编译得很好。

于 2012-05-23T12:59:09.387 回答