这次的主题是关于构造函数和析构函数
类的构造函数帮助类初始化对象的数据成员,任何对象的创建都会执行构造函数。
可以轻易地知道构造函数既有函数之名,很多地方可以说与普通函数无所区别。只有三个地方特异,一是函数名必须与类名相同,二是无返回类型,三是拥有初始化列表(唯一初始化const成员的地方,初始化顺序同样由函数参数列表决定(由右向左的顺序初始化))。其实还有一个值得注意的地方是构造函数不能定义成const类型,其中一个原因是方便创建一个const类型对象。
类的析构函数帮助类清理对象(栈区)所占空间,在在每一个对象的生命周期完毕时调用。
析构函数同样固定了函数名——~类名,没有返回类型,不能定义成const类型(对象都要被销毁了)。而且类里面定义有指针成员时,一般在析构函数里头delete指针成员,因为自己用指针开辟的内存区域不在栈区,而在堆区。调用析构函数的次序和对象作用区域内调用构造函数的次序相反。
下面来一小段代码。
#include<iostream>
using namespace std;
class demo
{
int a;
int *p;
public:
demo():a(0)
{
cout << "调用构造函数" << endl;
p = new int(0);
}
~demo()
{
cout << "调用析构函数" << endl;
delete p;
}
};
int main()
{
demo B, *C;
C = new demo;
delete C;
return 0;
}
运行结果1:
调用构造函数
调用构造函数
调用析构函数
调用析构函数
若是把C = new demo;和delete C注释掉,则运行结果2:
调用构造函数
调用构造函数
若是把delete C注释掉,则运行结果3:
调用构造函数
调用构造函数
调用析构函数
由运行结果1和2,容易想像到声明对象指针不调用构造函数,只有该指针new demo时才开始调用;再由运行结果1和3,也可以清楚的知道在delete对象指针时实质上是调用了类的析构函数,至于原因,你可以把delete看作一个函数,右边跟着的是它的参数,在本程序中右边跟着的是demo类型实参,在声明delete的时候形参肯定不是demo类型的,所以把该实参地址传给类的析构函数,因为析构函数能清楚的销毁这个对象。
构造和析构函数在继承方面的问题,下面也简单说说。
因为创建派生类对象时一定会调用该类的父类的构造函数,层层往上,直到一定会调用最高层级的父类的构造函数。所以在创建派生类对象时,从最高层级父类开始调用,再到下一层,直到本类构造函数。
而析构函数和构造函数相反,所以析构的对象从本派生类开始,之后,若是该派生类里面还定义有非基本类型的成员,则析构该成员对象,之后,再往上一层父类,同理,一直到最高层级父类才结束。
有关于构造和析构的讲解到此结束,还有疑问的地方欢迎提问。