1.再谈构造函数
1.1构造函数体赋值
在创建对象时候,编译器通过调用构造函数,给对象中的各个成员变量一个合适的初始值
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
经过构造函数后,对象中已经有了一个初始值,但是这不能成为对象的初始化,构造函数体内的语句最多称为赋初值,而不能称为初始化。因为:初始化只能初始化一次,而构造函数体内可以多次赋值
1.2初始化列表
冒号开头,逗号分隔,每一个成员变量后面跟着一个放在括号中的初始值或者表达式
class Date
{
public:
Date(int year, int month, int day)
: _year(year)
, _month(month)
, _day(day)
{}
private:
int _year;
int _month;
int _day;
}
注:
1.每个成员变量在初始化列表中只能出现一次(初始化只能一次)
2.类中包含以下成员,必须放在初始化列表位置进行初始化
🔴引用成员变量
🔴const成员变量
::const修饰的变量为常变量,具有常性(不可修改/二次赋值),只能在定义时赋值
🔴自定义类型成员(且该类没有默认构造函数时)
class A
{
public:
A(int a)
:_a(a)
{}
private:
int _a;
};
class B
{
public:
B(int a, int ref)
:_ab(a)
,_ref(ref)
,_n(10)
{}
private:
A _ab; // 没有默认构造函数
int& _ref; // 引用
const int _n; // const
};
3.成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后
次序无关
请看下题:
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();
}
A. 输出1 1
B.程序崩溃
C.编译不通过
D.输出1 随机值
按照声明次序初始化,先初始化_a2,_a1此时为随机值,初始化给_a2,所以_a2为随机值,接着初始化_a1,a为1,所以_a1为1,所以选D。
1.3总结
尽量使用初始化列表初始化,因为不管你是否使用初始化列表, 对于自定义类型成员变量,一定会优先使用初始化列表初始化。
初始化的步骤可以尽可能的放在一起,而构造函数体内就可以写其它的需求实现,增加代码的可读性