1、构造函数
规定在定义类对象的时候,必须调用适当的构造函数(constructor)完成对象的创建。特点是:
- 构造函数与类同名
- 构造函数没有返回类型
- 构造函数可以被重载
- 构造函数由系统自动调用,不允许在程序中显示调用。
需要注意的是:定义对象数组时,也要调用构造函数,所以必须要有不需要参数的构造函数(包括无参数构造函数和所有参数有缺省值的构造函数;构造函数应为公有成员,尽管是由编译系统进行饮食调用,但也是在类外进行的成员函数访问。
2、无参构造函数
默认构造函数
若一个类没有定义任何构造函数,则编译器会为它生成一个默认构造函数。默认构造函数是无参数的,负责对象的创建和初始化。
- 如果创建的是全局对象或静态对象,则默认构造函数将对象的位模式全部设置为0(可以理解为将所有数据成员初始化为0);
- 如果创建的是局部对象,则不会对对象的数据成员进行初始值设置。
缺省参数构造函数
如果显示定义了无参数的构造函数,又定义了全部参数都有默认值的构造函数,就容易在定义对象时产生二义性。
例如:
point(){ x = 0; y = 0;}
point(int a = 0, int b = 0){x = a; y = b;}
3、重载构造函数
重载的构造函数必须具有不同的函数原型,即参数个数、参数类型或参数次序不能完全相同。
如果有只有一个参数的构造函数,就可以Point p = 1这样定义;
4、拷贝构造函数
拷贝构造函数及指针悬挂问题
拷贝构造函数是根据已存在的对象初始化一个新建对象,若没有定义,则C++编译器将产生一个具有最小功能的默认拷贝构造函数,类似于:
X::X(const X& ){ }
默认拷贝构造函数以成员按位复制,但当一个类有指针类型的数据成员时,会造成指针悬挂。
当调用p2的析构函数时,p2会将所指向的自由存储单元归还系统,但p1仍然会指向此存储区域,这就是指针悬挂问题。当p1调用析构函数时就会出问题,因为p1指向的存储区域已被p2的析构函数释放了,不能再次释放。
定义拷贝构造函数
如果在一个类中要用一个已经存在的对象来初始化另一个对象,就会涉及拷贝构造函数的调用。如果类存在指针类型的数据成员,就应该为它提供拷贝构造函数。
拷贝函数的应用说明:
1.拷贝构造函数与一般的构造函数一样,与类同名,没有返回类型,可以重载。
2.拷贝构造函数的参数常常是const类型的本类对象的引用。
3.调用拷贝构造函数的时机是用已存在的对象初始化同类的新对象,以下几种情况会调用拷贝构造函数:
class X{};
X obj1;
X obj2 = obj1; // 1
X obj3(obj1); // 2
f(X o); // 3
X f(X x) {
...
return t; // 4
}
对于情况1,和以下代码是不同的:
X obj2;
obj2 = obj1;
这两条语句先调用无参构造函数建立obj2,再用赋值语句将obj1赋值给obj2,并不会调用拷贝构造函数。
构造函数与初始化列表
结构为:
构造函数名(参数表):成员1(初始值),成员2(初始值){
…
}
说明:
- 构造函数初始化列表中的成员初始化次序与它们在类中的声明次序相同,与初始列表中的次序无关。
- 构造函数初始化列表先于构造函数体中的语句执行。在一个类中,下列类成员必须采用初始化列表进行初始化:常量成员、引用成员、类对象成员以及派生类构造函数对基类构造函数的调用等。