派生类的析构函数的功能是在该类对象消亡之前进行的一些必要的清理工作。析构函数没有类型,也没有参数。
在派生过程中,基类的析构函数也不可以继承下来,如果需要析构的话,就要在派生类中声明新的析构函数。派生类析构函数的声明方法与没有继承关系中析构函数的析构函数的声明方法完全相同,只要在函数体中负责把派生类新增的非对象成员的清理工作做好就够了,系统会自己调用基类及对象成员的析构函数来对基类及对象成员进行清理。但她的执行次序和构造函数相反,首先执行析构函数的函数体,然后对派生类新增的类类型的成员对象进行清理,最后对所有从基类继承来的成员进行清理。这些清理工作分别是执行派生类析构函数、调用类类型的派生类对象成员所在类的析构函数和调用基类析构函数。对于这些析构函数的调用次序与对构造函数的调用次序完全相反。
如果没有显式声明某个类的析构函数,这种情况下,编译系统会自动为每个类都生成一个默认的析构函数,并在对象生存期结束时自动调用。这样自动生成的析构函数的函数体是空的,但并非不做任何事情,它会隐含地调用派生类对象成员所在类的析构函数和调用基类的析构函数。
【例】派生类析构函数举例
class B1//基类B1,构造函数有参数
{
public:B1(int i){cout << "基类B1的构造函数" << i << endl;}~B1(){cout << "基类B1的析构函数" << endl;}};class B2//基类B2,构造函数有参数
{
public:B2(int j){cout << "基类B2的构造函数" << j << endl;}~B2(){cout << "基类B2的析构函数" << endl;}};class B3//基类B3,构造函数无参数
{
public:B3(){cout << "基类B3的构造函数" << endl;}~B3(){cout << "基类B3的析构函数" << endl;}
};class D :public B2, public B1, public B3//派生类D,注意基类名的顺序
{
public://派生类的公有成员D(int a, int b, int c, int d) : b2(d), B2(b), B1(a), b1(c) {}//注意类名的个数与顺序,注意成员对象名的个数与顺序
private://派生类的私有成员对象B1 b1;B2 b2;B3 b3;
};int main()
{D d(1, 2, 3, 4);return 0;
}
运行结果:
分析:
程序中,给3个基类分别加入了析构函数,派生类没有做任何改动,仍然使用的是由系统提供的默认的析构函数。程序在执行时,首先执行派生类的构造函数,然后执行派生类的析构函数。派生类默认的析构函数又分别调用了成员对象及基类的析构函数,这时次序刚好和构造函数执行时相反。
【例2】
class B
{
public:B(int x = 0) :x(x){cout << "基类B构造函数" << endl;}B(B& b){cout << "基类B的拷贝构造函数" << endl;x = b.x;}~B(){cout << "基类B的析构函数" << endl;}void show1(){cout << "x的值为:" << x << endl;}int getX(){return x;}
private:int x;
};class D :public B
{
public:D(int a, int b, int c, int d) :B(a), y(b), z(c), v(d){cout << "派生类D的构造函数" << endl;}D(D& dd) :B(dd){cout << "派生类D的拷贝构造函数" << endl;x = dd.x;y = dd.y;z = dd.z;v = dd.v;}~D(){cout << "基类D的析构函数" << endl;}void show2(){cout << "x的值为:" << getX() << endl;cout << "y的值为:" << y << endl;cout << "z的值为:" << z << endl;cout << "v的值为:" << v << endl;}
private:int x;int y;int z;int v;
};int main()
{B b(5);b.show1();D d(1, 2, 3, 4);d.show2();D dd(d);dd.show2();return 0;
}
运行结果: