初始化列表,局部变量与数据成员

Initialization lists,local variables vs data members

本文关键字:数据成员 局部变量 列表 初始化      更新时间:2023-10-16
#include <iostream>
using namespace std;
class Ex {
private:
int i;
float f;
public:
Ex(int i,float f):i(i),f(f) {
cout << this->i << 't' << this->f << endl;
}
~Ex(){
cout << "destructor";
}
};
int main() {
Ex i(10,20.1f);
}

在上面我上面写的程序中,如果构造函数是参数化的构造函数,如下所示:

Ex(int i,float f){
i=i;
f=f;
cout << this->i << 't' << this->f << endl;
}

在这里,对象的数据成员被初始化为 Junk,因为数据成员由于同名的局部变量而被隐藏。 但是在上面的程序中,它工作正常,没有明确这一点。如何?

以前也问过类似的问题,例如这里和这里,但是虽然许多答案指出这是(与康斯坦丁D-Infragistics所说的相反)不是特定于编译器的,但我找不到任何实际引用标准相关部分的答案。

所以他们来了。我添加了强调以突出关键语句。

(§12.6.2/10)在非委托构造函数中,初始化按以下顺序进行:

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

(§12.6.2/12) mem 初始值设定项的表达式列表或大括号初始化列表中的名称在指定了 mem 初始值设定项的构造函数范围内计算。[ 示例:

class X {
int a;
int b;
int i;
int j;
public:
const int& r;
X(int i): r(a), b(i), i(i), j(this->i) { }
};

初始化X::r以引用X::a,使用构造函数参数的值初始化X::bi使用构造函数参数的值初始化X::ii,并使用X::i的值初始化X::j;每次创建类 X 的对象时都会发生这种情况。 — 结束示例 ]
[ 注意: 由于 mem 初始值设定项是在构造函数的作用域中计算的,因此可以在 mem 初始值设定项的表达式列表中使用this指针来引用正在初始化的对象。— 尾注 ]

因为以下几点,所有C++编译器都遵循以下几点:

构造
  1. 函数初始值设定项列表只能与类构造函数一起存在
  2. 在初始值设定项中,仅列出相同的类成员和基类 构造函数可以调用
  3. 初始化的顺序与类数据成员的顺序相同 已声明

当编译器将if视为初始值设定项列表的一部分时,它会立即标识为类成员,并且一切正常(第 2 点)。
如果你尝试除if以外的任何其他方法,编译器将给出错误。

在你做赋值的第两种情况下,编译器有 2 个候选if。它可以是类成员或局部变量。由于局部变量位于最内部的范围内,因此编译器将i视为i而不是this->i

编译器旨在将左侧if作为类作用域的成员,将右侧if作为构造函数作用域的成员。