C++初阶之类和对象》【初始化列表 + 自定义类型转换 + static成员】
·
什么是初始化列表?
初始化列表(Initializer List):是 C++ 中用于在对象构造时直接初始化成员变量的语法。
- 它位于构造函数的参数列表之后,函数体之前,以冒号
:开始,后面跟着用逗号分隔的成员变量初始化列表。 - 它核心作用是在对象内存分配完成后立即初始化成员,而非先默认初始化再赋值。
代码语言:javascript
AI代码解释
class MyClass
{
int _a;
double _b;
std::string _s;
public:
// 初始化列表语法
MyClass(int a, double b, const std::string& s)
: _a(a), _b(b), _s(s) // 初始化列表
{
// 构造函数体(此时成员已初始化)
}
};
为什么要使用初始化列表?
使用初始化列表主要有以下两点原因:
- 为了提高类的成员变量的初始化效率
- 有些成员变量不得不使用初始化列表进行初始化
--------------------为了提高效率--------------------
对于类类型的成员变量 :
- 如果没有使用初始化列表,在进入构造函数体之前,会先调用成员变量的默认构造函数
进行初始化,然后在构造函数体中再进行赋值操作,这会产生额外的开销。 - 而使用初始化列表,可以直接调用成员变量的合适构造函数
进行初始化,避免了先默认构造再赋值的过程,从而提高了初始化效率。- 例如:当成员变量是
string类型时,使用初始化列表可以直接调用string的构造函数来初始化,而不是先默认构造一个空字符串,再进行赋值。
- 例如:当成员变量是
代码语言:javascript
AI代码解释
class Student
{
string _name;
public:
// 低效写法:先默认构造空字符串,再赋值
Student(const std::string& name)
{
_name = name;
}
// 高效写法:直接调用string的拷贝构造
Student(const string& name) : _name(name) {}
};
--------------------不得不使用--------------------
初始化 const 成员和引用成员:
const成员变量和引用成员在定义后就不能被修改,因此必须在定义时进行初始化。- 初始化列表是在构造函数中初始化
const成员和引用成员的唯一方法。如果不使用初始化列表,试图在构造函数体中对const成员或引用成员进行赋值,将会导致编译错误。
代码语言:javascript
AI代码解释
----------------------------初始化 const 成员----------------------------
class ConstDemo
{
const int _value;
public:
ConstDemo(int v) : _value(v) {} // 必须用初始化列表
};
----------------------------初始化 const 成员----------------------------
class RefDemo
{
int& _ref;
public:
RefDemo(int& r) : _ref(r) {} // 必须用初始化列表
};
调用无默认构造的成员:
- 当成员变量的类没有默认构造函数,只有带参数的构造函数时,必须使用初始化列表来传递参数进行初始化。
- 否则,编译器无法找到合适的构造函数来初始化成员变量,从而引发编译错误。
代码语言:javascript
AI代码解释
class Engine
{
public:
Engine(int power) {} // 只有带参构造
};
class Car
{
Engine _engine;
public:
Car() : _engine(100) {} // 必须显式初始化
};
怎么使用初始化列表?
代码语言:javascript
AI代码解释
#include<iostream>
using namespace std;
// Time类定义
class Time
{
public:
/*---------------Time类的构造函数(带参数)---------------*/
// 注意:这个类没有提供默认构造函数(无参构造函数)
Time(int hour)
:_hour(hour)
{
cout << "Time类的构造函数Time()" << endl;
}
private:
int _hour;
};
// Date类定义
class Date
{
public:
/*---------------Date类的构造函数---------------*/
Date(int& x, int year = 1, int month = 1, int day = 1)
:_year(year) // 初始化_year
, _month(month) // 初始化_month
, _day(day) // 初始化_day
, _t(12) // 初始化Time类成员(必须提供参数)
, _ref(x) // 初始化引用成员(必须通过初始化列表)
, _n(1) // 初始化const成员(必须通过初始化列表)
{
// 如果尝试在构造函数体内初始化以下成员,会导致编译错误:
// 1. _t(12) - 错误:Time类没有默认构造函数
// 2. _ref = x - 错误:引用必须在初始化列表中初始化
// 3. _n = 1 - 错误:const成员必须在初始化列表中初始化
}
/*---------------打印日期信息---------------*/
void Print() const
{
cout << _year << "-" << _month << "-" << _day << endl; //const成员函数,保证不会修改对象状态
}
private:
int _year;
int _month;
int _day;
Time _t; // Time类成员(没有默认构造函数)
int& _ref; // 引用成员 (必须在初始化列表中初始化)
const int _n; // const成员 (必须在初始化列表中初始化)
};
int main()
{
int i = 0; //定义一个整型变量用于初始化Date的引用成员
// 创建Date对象d1
// 参数:
// i - 用于初始化_ref引用成员
// 其他参数使用默认值
Date d1(i);
// 调用Print方法输出日期信息
d1.Print();
return 0;
}
/*
* 关键点总结:
* 1. 初始化列表的必要性:
* - 必须用于初始化:引用成员(_ref)、const成员(_n)、没有默认构造函数的类成员(_t)
*
* 2. 初始化顺序:
* - 成员变量的初始化顺序由它们在类中的声明顺序决定(_year→_month→_day→_t→_ref→_n)
* - 与初始化列表中的书写顺序无关
*
* 3. 特殊成员初始化:
* - 引用和const成员:只能在初始化列表中初始化
* - 没有默认构造的类成员:必须在初始化列表中显式构造
*
* 4. 良好实践:
* - 即使对普通成员变量(如:_year)也使用初始化列表
* - 保持初始化列表顺序与成员声明顺序一致
*/

在这里插入图片描述
初始化列表 vs 构造函数体内赋值谁能获胜?
|
特性 |
初始化列表 |
构造函数内赋值 |
|---|---|---|
|
const成员 |
✔️ 支持 |
❌ 编译错误 |
|
引用成员 |
✔️ 支持 |
❌ 编译错误 |
|
无默认构造的成员 |
✔️ 支持 |
❌ 编译错误 |
|
性能 |
更高效(直接构造) |
可能低效(先默认构造再赋值) |
|
初始化顺序 |
由成员声明顺序决定 |
无顺序依赖 |
使用初始化列表的注意事项有哪些?
在 C++ 中,成员变量的初始化遵循两大规则:
其一:初始化顺序仅取决于变量在类中声明的先后次序,与初始化列表中的排列顺序无关。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)