在创建一个对象时 编译器通过调用构造函数 对对象中的每一个成员变量一个合适的初始值
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(1,1,1);
return 0;
}
上面例子中调用构造函数之后 对象中已经有了一个初始值 但不能将其称为对对象中的成员变量的初始化 构造函数体中的语句只能称之为赋初值 不能称为初始化时因为初始化只能初始化一次 而构造函数体内可以多次赋值(取最后一个值) 例如
Date(int year, int month, int day)
{
_year = year;
_year = 2023;
_month = month;
_day = day;
}
所以c++在这引入了初始化列表
初始化列表格式:以一个冒号开始,接着以逗号分隔成员变量列表 每个成员变量后面跟一个放在括号中的初值或者表达式
例如
Date(int year = 1,int month = 1,int day = 1)
:_year(year)
,_month(month)
,_day(day)
{}
1.每个成员变量在初始化列表中只能出现一次
因为初始化只能初始化一次 所以一个变量不能在初始化列表中多次出现
Date(int year = 1,int month = 1,int day = 1)
:_year(year)
,_year(1)//错误写法 不能多次进行初始化
,_month(month)
,_day(day)
{}
2.类中包含一下成员必须使用初始化列表初始化
class A
{
public:
A(int a)
{
_a = a;
}
private:
int _a;
};
class Date
{
public:
Date(int year = 1, int month = 2, int day = 3)
:_alias(day)
, _d(1)
, a1(1)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
int& _alias;//引用类型
const int _d;//cosnt类型
A a1;//自定义类型
};
在定义时就必须初始化的类型 那么就必须使用初始化列表进行初始化
3.尽量使用初始化列表初始化
对于自定义类型来说 几乎没有差别
但是对于自定义类型 使用初始化列可以提高代码的效率
举个栗子
class Time
{
public:
Time(int hour = 1)
{
_hour = hour;
}
private:
int _hour;
};
class Date
{
public:
Date(int hour)
:_t1(hour)//使用初始化列表
{}
private:
Time _t1;
};
如果不使用初始化列表 就得写成这样
class Time
{
public:
Time(int hour = 1)
{
_hour = hour;
}
private:
int _hour;
};
class Date
{
public:
Date(int hour)
{
Time t2(hour);//创建一个临时变量去调用Time类的构造函数
_t1 = t2;//调用默认赋值运算符重载函数
}
private:
Time _t1;
};
上面两种写法的区别显而易见 第一种写法只用调用一次构造函数即可完成初始化 第二种写法既要生成临时变量 还要调用赋值运算符重装函数
4.成员变量在类中声明的次序就是在初始化列表中初始化顺序 和其在初始化列表中的顺序无关
class Date
{
public:
Date(int year = 1, int month = 2, int day = 3)
:_alias(day)
,_year(year)
,_day(day)
,_month(month)
{}
private:
int _year;
int _month;
int _day;
int& _alias;
};
上面例子初始化顺序 _year->_month->_day -> _alias;
构造函数不仅可以构造和初始化对象 对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数 还具有类型转换的作用
class Date
{
public:
Date(int year)
:_year(year)
{}
private:
int _year;
};
int main()
{
Date d1 = 1;
return 0;
}
上面的代码 将一个整形类型1赋值给自定义类型d1 这其中存在隐式的类型转换
Date d1 = 1
等价于 Date tmp(1); Date d1(tmp);
编译器会先构造一个临时对象 再用临时对象拷贝构造d1
如果不想让构造函数支持隐式类型转换 在构造函数前加上关键字explicit即可
explicit Date(int year)
:_year(year)
{}
注意:不是所有的构造函数都支持类型转换
只有单参数的构造函数和第一个参数无默认值其余参数均有默认值的构造函数支持
Date(int year ,int month,int day)
:_year(year)
,_month(month)
,_day(day)
{}
//
Date(int year ,int month,int day = 1 )
:_year(year)
,_month(month)
,_day(day)
{}
比如这两种构造函数都不支持类型转换