之前复习了虚函数,今天来复习虚析构函数。
虚析构函数也是析构函数,它也没有返回值和参数。之所以叫它虚析构函数是因为在普通的析构函数之前加了一个virtual关键字。
虚析构函数的作用
我们先来定义这样的一个类A,然后B类继承它,在这两个类里面都声明了一个指针,我们在构造函数里给它们分配了内存空间,并且让它们指向了一个含有十个char类型的数据的数组。
class A { public: A() { cout << "A()" << endl; p = new char[10]; } ~A() { cout << "~A()" << endl; delete [] p; } private: char *p; }; class B : public A { public: B() { cout << "B()" << endl; pb = new char[10]; } ~B() { cout << "~B()" << endl; delete [] pb; } private: char * pb; };
在main函数中,我们声明一个A类型的指针,让其指向B的类的对象:
A *b = new B;
这样B类对象会自动调用其构造函数,调用构造函数的顺序就是从基类开始调用,然后是其派生类。等这个指针对象的工作做完后,我们会用delete让其释放资源,这个时候我们希望的应该是会把基类和派生类里面的所有资源都会回收,但是事实往往和我们所想的有所差别。
我们用delete b会出现这样的结果:
A() B() ~A()
很显然这不是我们想要的结果,之前我们复习的多态和这样的情况很类似,这个时候我们想释放派生类和基类的所有资源,但是现在只是释放了基类的资源。所以我们加上virtual将基类的机构函数变为虚析构函数。
class A { public: A() { cout << "A()" << endl; p = new char[10]; } virtual ~A() { cout << "~A()" << endl; delete [] p; } private: char *p; };
然后我们再执行上面的语句,这个时候就会出现我们想要的结果。
A() B() ~B() ~A()
注意构造函数和析构函数的调用顺序,虚构函数的调用顺序和构造函数的调用顺序是相反的。这样我们就成功的将基类和其派生类的资源回收掉了。
总结
如果我们想通过基类的指针将它和它所有的派生类的资源全都回收,也就是将它和它的派生类的析构函数都执行一遍,就要在基类的虚构函数前加上一个virtual让其变为虚析构函数。