C++ 初始化列表:成员变量的 “快速入场券”
关于构造函数请点这里
1. 语法形式
初始化列表以冒号(:
)开头,位于构造函数的参数列表之后、函数体之前,后跟一系列以逗号分隔的初始化字段。每个初始化字段由成员变量名和括号内的初始值(或用于初始化的表达式)组成。例如:
class MyClass {
private:
int num;
double d;
public:
MyClass(int n, double x) : num(n), d(x) {
// 构造函数体,这里可以有其他操作
}
};
2. 执行阶段
从概念上讲,构造函数的执行分为初始化阶段和计算阶段,初始化列表在初始化阶段起作用,且先于构造函数体内的计算阶段执行。所有类类型的成员都会在初始化阶段初始化,即便该成员未出现在初始化列表中,此时会调用其默认构造函数(若存在)。示例如下:
#include <iostream>
class Test1 {
public:
Test1() { std::cout << "Test1 default constructor" << std::endl; }
};
class Test2 {
public:
Test1 t1;
Test2() : t1() { // 这里的t1()可省略,因为会默认调用Test1的默认构造函数
std::cout << "Test2 constructor body" << std::endl;
}
};
int main() {
Test2 t;
return 0;
}
上述代码中,先调用Test1
的默认构造函数,再执行Test2
构造函数体的内容。
3.初始化必要成员 const和引用类型
对于const
成员变量、引用成员变量以及没有默认构造函数的类类型成员变量,必须在初始化列表中进行初始化。因为const
成员一旦初始化就不能更改,引用必须在定义时初始化且不能重新赋值,没有默认构造函数的类类型无法通过默认方式初始化。例如:
class MyClass {
private:
const int num;
int& ref;
class NoDefaultCtor {
public:
NoDefaultCtor(int n) : value(n) {}
int value;
};
NoDefaultCtor obj;
public:
MyClass(int n, int& r) : num(n), ref(r), obj(n) {
}
};
4. 初始化顺序
成员变量在初始化列表中的初始化顺序并非按照列表中的先后顺序,而是按照它们在类中声明的顺序进行初始化。因此,为了增强代码的可读性和避免潜在问题,建议初始化列表中成员的顺序与声明顺序保持一致。
class Example {
private:
int a;
int b;
public:
Example(int x)
: b(x),
a(b) {
// 这里a先于b被声明,所以先初始化a,此时b未初始化,a的值不确定
}
};
初始化列表总结:
⽆论是否显⽰写初始化列表,每个构造函数都有初始化列表;
⽆论是否在初始化列表显⽰初始化,每个成员变量都要⾛初始化列表初始化;