4

下面的代码给出了正确的输出,如果我声明变量ij,就像int i, j;

class A 
{
  int i, j;

public:
    A(int val) : i(val), j(i + 1)
    {
        cout<<i<<endl<<j<<endl;
    }
};

但是如果我声明变量iand j,就像int j, i;. 然后j打印垃圾值

class A 
{
  int j, i;

public:
    A(int val) : i(val), j(i + 1)
    {
        cout<<i<<endl<<j<<endl;
    }
};

那么,它是否取决于变量声明的顺序?

4

3 回答 3

2

它取决于变量声明的顺序吗?

是的,数据成员总是按照其声明的顺序进行初始化,这与成员初始化列表的顺序无关。

这意味着对于您的第二个代码片段,j始终在之前初始化i;但是当它被成员初始化器初始化时i仍然没有初始化。

对象的完整初始化顺序是:

(强调我的)

列表中成员初始化器的顺序无关紧要:实际初始化顺序如下:

1)如果构造函数是针对最派生类的,则虚基类按照出现的顺序进行初始化,深度优先从左到右遍历基类声明(从左到右指出现在基本说明符列表中)

2) 然后,直接基类按照从左到右的顺序初始化,因为它们出现在此类的基说明符列表中

3) 然后,按照类定义中的声明顺序初始化非静态数据成员

4) 最后执行构造函数的主体

于 2017-08-23T09:30:09.377 回答
2

它取决于变量声明的顺序吗?

绝对地!初始化列表中的初始化顺序被标准忽略;只有申报的顺序很重要。这样做是为了使“反向初始化顺序”在析构函数中有意义,即使可能存在多个构造函数,其初始化列表以不同的顺序排列。

以下是 C++ 标准 (12.6.2.10) 的相关部分:

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

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

[注意:声明顺序是为了确保基子对象和成员子对象以初始化的相反顺序被销毁。——尾注]

于 2017-08-23T09:30:12.660 回答
1

它取决于变量声明的顺序吗?

是的,数据成员(即:ij您的类A中)的初始化顺序对应于声明它们的顺序,而不是它们出现在构造函数的成员初始化器列表中的顺序。

类中构造函数的成员初始化列表A

A(int val) : i(val), j(i + 1)

没有说明这些数据成员的初始化顺序。

如果之前声明了数据成员(即:),则数据成员j仍将在之前初始化。在这种情况下正在初始化为,但此时未初始化,这可能导致包含垃圾。ijiint j, iji + 1ij


在 GCC 中,您可以通过提供-Wreorder选项在这些情况下显示警告,该选项已通过传递-Wall选项启用。

于 2017-08-23T09:28:42.563 回答