C++中什么时候使用初始化列表()

初始化程序列表用于初始化类的数据成员。构造函数将要初始化的成员列表表示为逗号分隔的列表, 后跟冒号。下面是一个使用初始化列表初始化Point类的x和y的示例。

#include< iostream> using namespace std; class Point { private : int x; int y; public : Point( int i = 0, int j = 0):x(i), y(j) {} /*The above use of Initializer list is optional as the constructor can also be written as: Point(int i = 0, int j = 0) { x = i; y = j; } */ int getX() const { return x; } int getY() const { return y; } }; int main() { Point t1(10, 15); cout< < "x = " < < t1.getX()< < ", " ; cout< < "y = " < < t1.getY(); return 0; }/* OUTPUT: x = 10, y = 15 */

上面的代码只是初始化列表的语法示例。在上面的代码中, x和y也可以在构造函数中轻松初始化。但是在某些情况下, 无法初始化构造函数内部的数据成员, 而必须使用” 初始化列表” 。以下是这种情况:
1)对于非静态const数据成员的初始化:
const数据成员必须使用初始化列表初始化。在以下示例中, ” t” 是Test类的const数据成员, 并使用初始化列表进行初始化。在初始化列表中初始化const数据成员的原因是因为没有为const数据成员单独分配内存, 因此将其折叠在符号表中, 因此我们需要在初始化列表中对其进行初始化。
另外, 它是一个复制构造函数, 我们不需要调用赋值运算符, 这意味着我们避免了一个额外的操作。
#include< iostream> using namespace std; class Test { const int t; public : Test( int t):t(t) {}//Initializer list must be used int getT() { return t; } }; int main() { Test t1(10); cout< < t1.getT(); return 0; }/* OUTPUT: 10 */

2)对于参考成员的初始化:
引用成员必须使用初始化列表进行初始化。在以下示例中, ” t” 是Test类的引用成员, 并使用初始化列表进行初始化。
//Initialization of reference data members #include< iostream> using namespace std; class Test { int & t; public : Test( int & t):t(t) {}//Initializer list must be used int getT() { return t; } }; int main() { int x = 20; Test t1(x); cout< < t1.getT()< < endl; x = 30; cout< < t1.getT()< < endl; return 0; } /* OUTPUT: 20 30 */

3)对于没有默认构造函数的成员对象的初始化:
在以下示例中, 类” A” 的对象” a” 是类” B” 的数据成员, 而” A” 没有默认的构造函数。初始化列表必须用于初始化” a” 。
#include < iostream> using namespace std; class A { int i; public : A( int ); }; A::A( int arg) { i = arg; cout < < "A's Constructor called: Value of i: " < < i < < endl; }//Class B contains object of A class B { A a; public : B( int ); }; B::B( int x):a(x) {//Initializer list must be used cout < < "B's Constructor called" ; }int main() { B obj(10); return 0; } /* OUTPUT: A's Constructor called: Value of i: 10 B's Constructor called */

如果类A同时具有默认构造函数和参数化构造函数, 则如果要使用默认构造函数初始化” a” , 则不必使用” 初始化列表” , 而必须使用参数化构造函数初始化” a” 。
4)对于基类成员的初始化:像第3点一样, 只能使用Initializer List调用基类的参数化构造函数。
#include < iostream> using namespace std; class A { int i; public : A( int ); }; A::A( int arg) { i = arg; cout < < "A's Constructor called: Value of i: " < < i < < endl; }//Class B is derived from A class B: A { public : B( int ); }; B::B( int x):A(x) { //Initializer list must be used cout < < "B's Constructor called" ; }int main() { B obj(10); return 0; }

5)当构造函数的参数名称与数据成员相同时
如果构造函数的参数名称与数据成员名称相同, 则必须使用以下方法初始化数据成员
这个指针
或初始化列表。在以下示例中, A()的成员名称和参数名称均为” i” 。
#include < iostream> using namespace std; class A { int i; public : A( int ); int getI() const { return i; } }; A::A( int i):i(i) { }//Either Initializer list or this pointer must be used /* The above constructor can also be written as A::A(int i) { this-> i = i; } */int main() { A a(10); cout< < a.getI(); return 0; } /* OUTPUT: 10 */

6)由于性能原因:
最好在Initializer List中初始化所有类变量, 而不是在body内部分配值。考虑以下示例:
//Without Initializer List class MyClass { Type variable; public : MyClass(Type a) {//Assume that Type is an already //declared class and it has appropriate //constructors and operators variable = a; } };

在这里, 编译器按照以下步骤创建类型为MyClass的对象
1.首先为” a” 调用Type的构造函数。
2.在MyClass()构造函数的内部调用” 类型” 的赋值运算符进行赋值
variable = a;

3.然后, 由于” 类型” 的析构函数超出范围, 因此最终将其称为” a” 。
现在考虑使用带有初始化器列表的MyClass()构造函数的相同代码
//With Initializer List class MyClass { Type variable; public : MyClass(Type a):variable(a) {//Assume that Type is an already //declared class and it has appropriate //constructors and operators } };

使用初始化程序列表, 编译器执行以下步骤:
1.调用” Type” 类的副本构造函数进行初始化:变量(a)。初始化程序列表中的参数用于直接复制构造” 变量” 。
2.” 类型” 的析构函数被称为” a” , 因为它超出了范围。
从本示例可以看出, 如果在构造函数主体内使用赋值, 则有三个函数调用:构造函数+析构函数+一个附加赋值运算符调用。如果我们使用Initializer List, 则只有两个函数调用:复制构造函数+析构函数调用。看到这个在这一点上发布一个正在运行的示例。
在” 实际” 应用程序中会有很多这样的变量, 这种分配惩罚将更多。谢谢ptr添加这一点。
【C++中什么时候使用初始化列表()】如果发现任何不正确的地方, 或者想分享有关上述主题的更多信息, 请写评论。

    推荐阅读