[本节内容]
再谈构造函数
1.构造函数赋初值
2.初始化列表
3.explicit关键字
之前博客讲过成员函数默认的构造函数:https://blog.youkuaiyun.com/ly_6699/article/details/87870429
类的六个默认成员函数也在下面博客中讲到
类与对象:https://blog.youkuaiyun.com/ly_6699/article/details/87870429
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.类中包含以下成员时必须放在初始化列表中进行初始化:
引用成员变量
const成员变量
类类型成员(该类没有默认的构造函数)
class A
{
public:
A(int a)
:_a(a)
{}
private:
int _a;
};
class B
{
public: //初始化
B(int a, int ref)
:_aobj(a)
, _ref(ref)
, _n(10)
{}
private: //声明
A _aobj; //类类型且没有默认的构造函数
int & _ref; //引用
const int _n; //const
};
3.尽量使用初始化列表进行初始化,因为无论我们是否使用初始化列表,自定义类型的成员一定会先使用初始化列表进行初始化
class Time
{
public:
Time(int hour = 0)
:_hour(hour)
{
cout << "Time()" << endl;
}
private:
int _hour;
};
class Date
{
public:
Date(int day)
{}
private:
int _day;
Time _t;
};
int main()
{
Date d(1);
system("pause");
return 0;
}
4.成员变量在类中的声明次序决定了初始化次序
class Array
{
public:
Array(int size)
:_size(size)
,_array((int *)malloc(sizeof(int)*_size)) //错误代码! 由于要先初始化了_array,而此时的_size还未初始化
{}
private:
int* _array;
int _size;
};
3.explicit 关键字
构造函数不仅可以构造初始化对象,对于单个参数的构造函数,还具有类型转换的作用。
class Date
{
public:
/*Date(int year)
:_year(year)
{}*/
explicit Date(int year) //禁止隐式类型转换
:_year(year)
{}
void show()
{
cout << _year << endl;
cout << _month << endl;
}
private:
int _year;
int _month;
};
void Test()
{
Date d1(2018); //_year=2018,_month为随机值
Date d2 = 12; //因为有 explicit,故编译失败
//d2 隐式类型转换的过程:
//1.用整型12构造一个匿名对象
//2.匿名对象拷贝构造d2
//3.优化为拷贝构造
}
用explicit 修饰的构造函数,将会禁止单参构造函数的隐式类型转换