目录
1.初始化列表
(1)初始化列表的概念
在前面的文章实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有一种方式,就是初始化列表,初始化列表的使用方式是以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式:
cpp
class Time
{
public:
Time(int hour)
:_hour(hour)
{
}
private:
int _hour;
};
class Date
{
public:
Date(int& x, int year = 1, int month = 1, int day = 1)
:_year(year)
,_month(month)
,_day(day)
,_t(12)
,_ref(x)
,_n(1)
{
}
void Print() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
Time _t;
int& _ref;
const int _n;
};
int main()
{
int i = 0;
Date d1(i);
d1.Print();
return 0;
}
每个成员变量在初始化列表中只能出现一次,语法理解上初始化列表可以认为是每个成员变量定义 初始化的地方。
(2)成员变量走初始化列表的逻辑

另外,初始化列表还有一些要注意的点:
①初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的的先后顺序无关,建议声明顺序和初始化列表顺序保持一致。
②无论是否显式写初始化列表,每个构造函数都有初始化列表。
③无论是否在初始化列表显式初始化成员变量,每个成员变量都要走初始化列表初始化,所以尽量使用初始化列表初始化。
下面看一道例题:
下面程序的运行结果是什么()
A. 输出1 1
B. 输出2 2
C. 编译报错
D. 输出1 随机值
E. 输出1 2
F. 输出2 1
cpp
#include<iostream>
using namespace std;
class A
{
public:
A(int a)
:_a1(a)
,_a2(_a1)
{}
void Print()
{
cout << _a1 << " " << _a2 << endl;
}
private:
int _a2 = 2;
int _a1 = 2;
};
int main()
{
A aa(1);
aa.Print();
}
既然在初始化列表显式初始化了成员变量,那成员变量声明处加的缺省值就可以直接忽略。初始化列表中按照成员变量在类中声明顺序进行初始化,所以先初始化的是_a2,此时_a1还没有被初始化,故是随机值,_a2被赋为随机值,再初始化_a1,_a1用传递的参数初始化,被初始化为1。故这道题选D
2.隐式类型转换
C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。
cpp
#include<iostream>
using namespace std;
class A
{
public:
A(int a1)
:_a1(a1)
{}
private:
int _a1 = 1;
};
int main()
{
A aa1 = 1;
aa1.Print();
}
这里的隐式转换是用1去构造临时对象,再用临时对象拷贝构造aa1,但编译器优化后会直接构造,即使类里写了拷贝构造函数,也会用直接构造函数。
const A& aa2 = 1;
这个语句不能不加const,因为1构造临时对象,临时对象具有常性,必须加const;