这次我们来介绍一下类的特殊的成员函数——构造函数。每个类都定义了其对象被初始化的方式,类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数统称做构造函数。
构造函数的任务就是初始化类的数据成员,只要有类的对象被创建,就会执行构造函数。
首先我们来讲讲构造函数的具体实现:
- 构造函数的名字与类名相同
- 构造函数没有返回值
- 构造函数有一个(可能为空的)参数列表和一个(可能为空的)函数体
- 构造函数可以有自己的初始换列表
例:
class S
{
public:
S(int _i,int _m,int _n):
i(_i),m(_m),n(_n)
{
//构造函数的函数体可以为空
}
private:
int i;
int m;
int n;
};
构造函数还有如下特点
- 一个类中可以包含多个构造函数,即它可以重载,但是不同的构造函数之间必须在参数的数量或参数的类型上有所区别
- 如果你的类中没有定义任何构造函数,那么编译器会自动为你生成一个无需任何实参的默认构造函数,叫做合成的默认构造函数
- 构造函数的初始值在某些情况下必不可少:如果成员是const、引用、或者属于某种未提供默认构造函数的类类型
- 类成员的初始化顺序与它们在类中定义出现的顺序一致,构造函数中初始化列表的初始值的前后位置关系不会影响实际的初始化的顺序。所以建议大家最好令构造函数初始值的顺序与成员声明的顺序保持一致
- 构造函数不能被声明为const,因为当我们创建一个类的const对象时,直到构造函数完成初始化过程,对象才能真正取得其“常量”属性,这样的话,构造函数在const对象的构造过程中可以向其写值。
特点2具体说明:
当对象被默认初始化或值初始化时自动执行默认构造函数。默认构造函数在以下情况下发生:
- 当我们在块作用域内不使用任何初始值定义一个非静态变量
- 当一个类的本身含有类类型的成员且使用合成的默认构造函数时
- 当类类型的成员没有在构造函数初始值列表中显式地初始化时
特点3实例:
class S
{
public:
S(int _i)
{
i=_i;
m=_i; //不能给const赋值
n=i; //引用变量n没有被初始化
}
private:
int i;
const int m;
int &n;
};
特点4实例:
class S
{
public:
S(int _i):
i(m),m(_i) //由于i在m之前初始化,所以操作未定义
{
//构造函数的函数体可以为空
}
private:
int i;
int m;
};
最后,我们来讲一下explicit,这个关键字是用来修饰构造函数的,是为了一致构造函数定义的隐式转化。
它有以下几点注意的地方:
- explicit只对一个实参的构造函数有效,需要多个实参的构造函数不能用于执行隐式转换,所以无需指定为explicit的
- 只能在类内声明构造函数时使用explicit关键字
- explicit构造函数只能用于直接初始化
explicit注意事项3详解:
当我们执行拷贝形式的初始化时,会发生隐式转换,此时我们只能使用直接初始化而不能使用explicit构造函数。