目录
1. 含义 和 基本语法
2. 为什么使用初始化列表?
2.1 使用初始化列表,效率更高
2.2 有些成员必须使用初始化列表
3.初始化顺序
4. 给缺省值初始化
5. 与在函数体内赋值的区别
1. 含义 和 基本语法
含义:
- 之前学过的构造函数初始化,是以在函数体内赋值的方式初始化的,
- 而初始化列表是构造函数的一部分,用于在创建对象时直接初始化成员变量,而不是先在函数体内赋值。
语法:
class A { int x; const int y; int& r; public: A(int a, int b, int& ref) : x(a), y(b), r(ref) { // 函数体 } };
冒号
:后面是初始化列表。每个成员用 成员名(值)或 成员名 {值}(C++11)表示。
多个成员用逗号分隔。
2. 为什么使用初始化列表?
2.1 使用初始化列表,效率更高
首先要知道:C++规定,一个对象在真正进入构造函数的大括号
{}之前,它的所有成员变量都已经完成了 初始化。
在函数体内赋值:
class Date { public: // 函数体内赋值的方式初始化 Date(int year,int month,int day) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; };
初始化阶段(进入大括号前):编译器先给
_year和_month分配内存。由于没在初始化列表里写,编译器会执行默认初始化。对于内置类型int,就是随便填个随机垃圾值(比如_year现在是乱码)。赋值阶段(进入大括号后):执行
_year = year;,把参数的值赋给原本已是垃圾值的_year。使用初始化列表:
class Date { public: // 初始化列表初始化 Date(int year, int month, int day) :_year(year), _month(month), _day(day) {} private: int _year; int _month; int _day; };
初始化阶段(进入大括号前):编译器分配内存的同时,直接用参数
year来构造_year。一步到位,没有垃圾值,也没有后续的赋值操作。效率差距在哪里?
对于 内置类型,赋值和初始化效率一样,就是改内存。
但如果成员变量是自定义类型,差别就巨大了:
- 假设类里有个成员对象,对它赋值初始化,会先调用它的默认构造,进入大括号后,再调用赋值运算符重载。一共经历了两次函数调用。
- 而用初始化列表初始化,直接调用它的拷贝构造函数。只有一次函数调用,效率更高。
2.2 有些成员必须使用初始化列表
- const 成员:因为不能在函数体内赋值初始化,所以只能只能用初始化列表初始化
- 引用:必须在定义时绑定,不能重新绑定
- 没有默认构造的类:因为对类进行初始化时,会调用它的默认构造,如果它没有默认构造,就会报错,所以没有默认构造的类必须用初始化列表初始化
3.初始化顺序
成员初始化顺序由它们在类中声明的顺序决定,与初始化列表中的书写顺序无关。如下:
4. 给缺省值初始化
可以在声明成员时直接给默认值:
class A { int x = 0; int y = 1; public: A(int a) : x(a) {} // y 仍使用默认值 1 };如果成员在初始化列表中也被指定,则缺省值被忽略,比如上面代码中,x在初始化列表被初始化,缺省值被忽略。
5. 与在函数体内赋值的区别
| 方式 | 过程 | 适用性 |
|---|---|---|
| 初始化列表 | 直接调用构造函数/初始化 | 所有成员,包括 const、引用、无默认构造的类类型 |
| 函数体内赋值 | 先默认构造,再调用赋值运算符 | 仅适用于可默认构造且可赋值的成员 |