概念
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括 号中的初始值或表达式
class Date
{
public://初始化列表Date(int year,int month,int day):_year(year),_month(month),_day(day){}private://声明int _year = 1;//缺省值int _month = 1;int _day;const int _n;
};int main()
{//对象实例化Date d1(2024, 1, 31);return 0;
}
【注意】
1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
class Date
{
public:Date(int year, int month, int day):_year(year), _month(month), _day(day), _n (2),_year(3){}private://声明int _year = 1;//缺省值int _month = 1;int _day;const int _n;
};int main()
{//对象实例化Date d1(2024, 1, 31);return 0;
}
初始化列表能只能初始化一次,多次初始化会报错如下:
2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
- 引用成员变量
class A
{
public:A(int a ):_a(a){cout << "A(int a=0)" << endl;}private:int _a;
};class Date
{
public://初始化列表是每个成员变量定义初始化的位置Date(int year, int month, int day),_month(2),ref(year){//赋值修改_year = year;_month = month;_day = day;//ref=year;//引用成员变量不能在函数体内初始化}private://声明int _year = 1;//缺省值int _month = 1;int _day;int& ref;
};int main()
{//对象实例化Date d1(2024, 1, 31);return 0;
}
const
成员变量
class Date
{
public://初始化列表是每个成员变量定义初始化的位置Date(int year, int month, int day):_n(1)//const成员变量必须使用初始化列表进行初始化,_month(2){//赋值修改_year = year;_month = month;_day = day;//_n = 2;//const成员变量不能在函数体内初始化}private://声明int _year;int _month;int _day;const int _n;
};int main()
{//对象实例化Date d1(2024, 1, 31);return 0;
}
- 没有默认构造函数的自定义类型成员变量
class Date
{
public://初始化列表是每个成员变量定义初始化的位置Date(int year, int month, int day),_month(2),_a(20)//没有默认构造函数的自定义类型成员变量必须在初始化列表进行初始化{//赋值修改_year = year;_month = month;_day = day;}private://声明int _year = 1;//缺省值int _month = 1;int _day;const int& ref;A _a;const int _n;
};int main()
{//对象实例化Date d1(2024, 1, 31);return 0;
}
const
成员变量、引用成员变量、没有默认构造函数的自定义类型成员变量必须在初始化列表内初始化的原因:
①初始化列表是对象的成员变量定义的地方。
②对象的内置类型成员变量在初始化列表定义时没有要求必须初始化,因此既可以在初始化列表进行初始化,也可以在构造函数体内初始化。
③而const
成员变量、引用成员变量、没有默认构造函数的自定义类型成员变量不能先定义再初始化,它们在初始化列表内定义,并且必须在定义时就初始化,因此必须在初始化列表内初始化。
3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
为什么会先使用初始化列表初始化?
因为自定义类型成员需要调用构造函数进行初始化,这个构造函数只能在初始化列表中调用,即使不写出来,编译器也会添加到初始化列表进行初始化
4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
观察下面代码,会是哪个结果:
A. 输出1 1
B.程序崩溃
C.编译不通过
D.输出1 随机值
class A
{
public:A(int a):_a1(a),_a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}//private:int _a2;int _a1;
};int main()
{A aa(1);aa.Print();return 0;
}
上面代码,类成员变量中先声明了_a2
,再声明了_a1
,因此初始化的顺序是先初始化_a2
,再初始化_a1
。先声明_a2
就会先初始化_a2
,用_a1
初始化_a2
,由于此时_a1
还是随机值,因此_a2
的值也是随机值,_a1
使用a
的值1进行初始化,因此,_a1
的值为1。
所以,建议类中的成员变量声明的顺序和初始化列表中初始化的顺序一致。
初始化列表其他注意点
class A
{
public:A(int a = 0, int b = 0):_a(a){cout << "A(int a=0)" << endl;}private:int _a;
};class Date
{
public://初始化列表是每个成员变量定义初始化的位置Date(int year, int month, int day):_n(1)//const成员变量必须使用初始化列表进行初始化, _month(2), ref(2), _a(20, 10)//没有默认构造函数的自定义类型成员变量必须在初始化列表进行初始化, _p((int*)malloc(sizeof(4)*10))//初始化列表不能写多条语句{//赋值修改_year = year;_month = month;_day = day;//_n = 2;//const成员变量不能在函数体内初始化if (_p == nullptr){perror("malloc fail");}}private://声明//缺省值是给初始化列表用的int _year = 1;//缺省值int _month = 1;int _day;const int& ref;A _a;const int _n;int *_p;
};int main()
{//对象实例化Date d1(2024, 1, 31);A a(5, 5);return 0;
}
①初始化列表是每个成员变量定义初始化的位置
②缺省值是给初始化列表用的
③初始化列表不能写多条语句