构造函数初始化列表
时间线:
调用构造函数 Example obj(10)
进入构造函数前,所有数据成员已经分配内存
const 成员 value 必须在此刻初始化(因为它不能改变)
进入构造函数体 { ... }
此时 value 如果还未初始化,就无法再初始化了
在进入构造函数体中,已经为成员变量分配了空间,所以const修饰的成员变量和引用变量需要使用初始化列表进行初始化
对于自定义成员变量如果不写初始化列表的话,就会走自定义成员变量的默认构造函数,如果没有默认的构造函数就会报错

总结下来有三种情况必须走初始化列表
- 引用成员变量
- const成员变量
- 自定义成员变量(该类没有默认的构造函数时)
尽量走初始化列表初始化,因为不管你是否使用初始化列表,对于自定义成员变量一定会调用初始化列表
成员变量在类中的声明顺序和在初始化列表中的先后顺序无关,建议初始化列表顺序和声明顺序一致
一些初始化和检查工作,初始列表不能做
explicit关键字
用expilicit修饰构造函数,将会禁止构造函数的隐式转换
a.单参数隐式类型转换
cpp
class Date {
int year, month, day;
public:
explicit Date(int y) : year(y), month(1), day(1) { // 防止隐式转换
std::cout << "Date from year: " << year << std::endl;
}
Date(int y, int m, int d) : year(y), month(m), day(d) { }
};
void scheduleEvent(const Date& date) {
std::cout << "Event scheduled" << std::endl;
}
int main() {
Date d1(2024); // ✅ 显式构造
Date d2 = 2024; // ❌ 编译错误(有 explicit)
scheduleEvent(Date(2024)); // ✅ 显式转换
// scheduleEvent(2024); // ❌ 编译错误(有 explicit)
Date d3(2024, 1, 1); // ✅ 多参数构造
return 0;
}
b.多参数隐式类型转换
cpp
class Point {
int x, y;
public:
explicit Point(int a, int b) : x(a), y(b) { } // C++11 支持
};
void drawPoint(const Point& p) {
std::cout << "Drawing point" << std::endl;
}
int main() {
Point p1(10, 20); // ✅ 显式构造
Point p2 = {10, 20}; // ❌ 编译错误(C++11,有 explicit)
Point p3{10, 20}; // ✅ C++11 统一初始化
drawPoint(Point(10, 20)); // ✅ 显式
// drawPoint({10, 20}); // ❌ 编译错误(有 explicit)
return 0;
}
static修饰的成员变量
用static修饰的成员变量,称之为静态成员变量,静态成员变量是全局变量,一定过要在类初始化,属于这个类的所有对象,不能给缺省值。
static成员变量不走初始化列表,因为它属于整个类,而非某个实例的全局静态变量,声明和定义要分离
cpp
class A
{
public:
A() { _a++; }
~A() { _a--; }
A(const A& a) { ++_a; }
static void Print()
{
std::cout << _a << std::endl;
}
private:
static int _a;//所有的实例共享一个静态成员变量
};
int A::_a = 0;//定义和声明分离
int main()
{
A::Print();
A a1, a2;
A a3(a1);
A::Print();
return 0;
}
特点
- 静态成员变量为所有的实例共享,存放在静态区
- 静态成员变量必须要在类外定义,定义时候不添加static,类中只是声明
- 静态成员变量可以通过类名::静态成员,对象.静态成员来访问
- 静态成员也是类的成员,受public,protected,private访问限定符限制
- 静态成员变量没有隐藏的this指针,不能访问任何非静态成员变量(逻辑上来说,选择不了访问哪个实例的成员)