在C++的类中,都会有一个或多个构造函数、一个析构函数、一个赋值运算操作符。即使我们自己定义的类中,没有显示定义它们,编译器也会声明一个默认构造函数、一个析构函数和一个赋值运算操作符。例如:
//声明一个空类
class Empty{};
//但是这个空类和下面这个类是等同的
class Empty
{
Empty(){.....}; //默认构造函数
Empty( const Empty & rhs ){......} //复制构造函数
~Empty(){..........} //析构函数
Empty operator * (const Empty & rhs){.........}
};
值得注意的是,只有当这些函数被调用的时候,他们才会被编译器创建出来。
如果我们已经声明了一个构造函数,那么编译器将不会再创建一个默认构造函数。
下面来详细介绍一下构造函数和析构函数。
1.构造函数
构造函数(constructor)是与类同名的特殊成员函数,主要用于初始化对象的数据成员。定义形式如下:
class X
{
// .......
X(); //无参构造函数
X(......); //有参构造函数,构造函数支持重载
// .........
}
构造函数的声明和定义方法与类的其他成员函数相同,可以在类的内部定义构造函数,也可以先在类中声明构造函数,然后在类外进行定义。在类外定义构造函数的形式如下:
1 X :: X(.....) 2 { 3 //........... 4 }
构造函数具有以下几个特点:
(1)构造函数与类同名
(2)构造函数没有返回类型,void也不行
(3)构造函数可以被重载
(4)构造函数由系统自动调用,不允许在程序中显示调用它
(5)构造函数的调用时机是定义对象之后的第一时间,即构造函数是对象的第一个被调用的函数
(6)定义对象数组或用new创建动态对象时,也要调用构造函数。但定义数组对象时,必须有无参构造函数
(7)构造函数通常应定义为共有成员(当然也可以定义为私有的,但不能被类外部访问。单例模式就用到私有化的构造函数)
同时还需注意一下几点:
(1)构造函数初始化列表中的成员初始化次序与它们在类中声明的次序相同,与其在初始化列表中的次序无关。如:
1 Tdate::Tdate(int m , int d , int y):month(m),day(d),year(y){} 2 Tdate::Tdate(int m , int d , int y):year(y),month(m),day(d){} 3 Tdate::Tdate(int m , int d , int y):day(d),year(y),month(m){} 4 //以上三个构造函数完全相同
(2)构造函数初始化列表先于构造函数体中的语句执行
(3)以下类成员必须使用成员初始化列表进行初始化:常量成员、引用成员、类对象成员、派生类构造函数对基类构造函数的调用
1.1默认构造函数
默认构造函数是指不需要显示提供参数的构造函数。在某些情况下,必须使用默认构造函数来定义对象(如对象数组)
如果一个类没有定义任何构造函数,在需要时编译器将会为它生成一个默认构造函数,它只负责创建对象,不做任何初始化工作。
在用默认构造函数创建对象时,如果创建的是全局对象或静态对象,则对象的位模式全为0(可以理解为将所有数据成员初始化为0);如果创建的是局部对象,不进行对象数据成员的初始化,对象数据成员是未知的。
注意:只有在类没有定义任何构造函数时,系统才会产生默认构造函数。一旦定义了任何形式的构造函数,系统将不再产生默认构造函数。
我们可以对默认构造函数进行重定义,来为对象的数据成员提供初始值。同时我们还可以为参数提供默认值。
1.2重载构造函数
重载构造函数必须具有不同的函数原型(即参数个数、参数类型或参数次序不能完全相同)
1.3复制构造函数
复制构造函数是一个特殊的构造函数,用于根据已存在的对象初始化一个新建对象。
如果没有定义类的复制构造函数,在需要时,C++编译器将产生一个具有最小功能的默认复制构造函数,形式如:X::X(const X&){}