构造函数 构造函数体赋值 与 初始化列表
1.构造函数体赋值
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称作为类对象成员的初始化,构造函数体中的语句只能将其称作为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。
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.类中包含以下成员,必须放在初始化列表位置进行初始化 不能使用函数体内初始化
a. 引用成员变量
b. const 成员变量
c.自定义类型成员 该类没有默认构造函数
3.尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会 先 使用初始化列表初始化.
严格来说对于内置类型,其实使用初始化列表和函数体内初始化是没有差别
自定义类型,最好使用初始化列表 效率更高
class Date
{
public:
// 自定义类型, 使用初始化列表 -> 构造函数
// Date(int day , int hour)
// :_t(hour)
// {}
//自定义类型 不使用初始化列表 函数体内初始化-> 构造函数 + operator=
Date(int day , int hour)
{
Time t(hour);
_t = t;
}
private:
int _day;
Time _t;
};
- 成员变量在类中 声明次序 就是其在初始化列表中的初始化顺序, 与其在初始化列表中的先后顺序无关
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 随机值
声明次序 就是其在初始化列表中的初始化顺序
建议 好的习惯 类中成员变量声明的顺序和初始化列表出现的顺序保持一致
3.explicit关键字
用explicit修饰构造函数,将会禁止单参构造函数的隐式转换
构造函数不仅可以构造与初始化对象,对于单个参数的构造函数,还具有类型转换的作用。
int main()
{
//单参数的构造函数,支持隐式类型转换
Class_A a1(1);
Class_A a2 = 2;
//语法意义上是 先构造 在拷贝构造
//早期编译器 : Class_A tmp(2) + Class_A a2(tmp)
//现在编译器 : 做了优化,直接调用构造函数 Class_A a2(2)
}
class Class_A
{
public:
explicit Class_A(int a)
//explicit修饰构造函数,将会禁止单参构造函数的隐式转换
{
}
private:
};
int main()
{
//单参数的构造函数,支持隐式类型转换
Class_A a1(1);
//编译器报错
Class_A a2 = 2;
//语法意义上是 先构造 在拷贝构造
//早期编译器 : Class_A tmp(2) + Class_A a2(tmp)
//现在编译器 : 做了优化,直接调用构造函数 Class_A a2(2)
}