为什么在类作用域中定义变量的顺序并不重要?

Jib*_*bel 8 c++ variables scope initialization

如果我们在任何函数中执行这两行,我们都会得到一个错误,这是合乎逻辑的,因为变量b是在初始化之后定义的a = b

int a = b;
int b = 0;
Run Code Online (Sandbox Code Playgroud)

但是当我们将这两行插入到类的作用域中时,为什么类不关心定义的顺序呢b

class Foo
{
    int a = b;
    int b = 0;
};
Run Code Online (Sandbox Code Playgroud)

for*_*818 14

声明类中成员的顺序确实很重要。

该顺序决定了它们的初始化顺序。使用示例中的默认初始值设定项大致相当于将此构造函数与成员初始值设定项列表一起使用:

class Foo
{
    int a;
    int b;
    Foo() : a(b) , b(0) {}   // !! undefined !!
};
Run Code Online (Sandbox Code Playgroud)

在这里,初始化的顺序仍然由声明成员的顺序决定,而不是由它们在成员初始值设定项列表中的顺序决定。当顺序不同时,编译器通常会发出警告。不过,在上面的问题变得更加明显:在初始化之前a进行初始化。在其初始化之前读取是未定义的行为。bbb

要正确地用另一个成员的值初始化一个成员,您必须遵守以下顺序:

class Foo
{
    int b = 0;  // initialized first
    int a = b;  // OK
};
Run Code Online (Sandbox Code Playgroud)


Som*_*ude 13

当您定义这两个非成员变量时,它们将立即被初始化。

当定义两个成员变量时,初始化将在构造对象时发生,而不是在定义变量时发生。

然而初始化是按照声明顺序进行的,因此初始化a将使用未初始化和不确定的值,b这会导致未定义的行为

  • @Jibel 并不总是如此。如果你交换它们的声明,它们会按正确的顺序初始化,一切都很好 (3认同)

x6d*_*fb8 7

我想补充一点:

非限定名称查找中,“成员函数定义”部分说:

对于成员函数体内使用的名称、成员函数的默认参数、成员函数的异常规范或默认成员初始值设定项,搜索的范围与类定义中的相同,只不过类的整个范围被考虑,而不仅仅是使用该名称的声明之前的部分。

所以你甚至可以b在类中声明之前使用这里。


更新:正如其他答案所说,a是用 初始化的b,但在b初始化之前。请参阅https://godbolt.org/z/MT86nd3Yr,您可以发现它a实际上具有垃圾值。