虚析构函数
在C++中,不能声明虚构造函数,但是可以声明虚析构函数。语法为
virtual ~类名();
如果一个类的析构函数是虚函数,那么,由它派生而来的所有子类的析构函数也是虚函数。析构函数设置为虚函数之后,在使用指针引用时可以动态绑定,实现运行时的多态,保证使用基类类型的指针就能够调用适当的析构函数针对不同的对象进行清理工作。
简单来说,如果有可能通过基类指针调用对象的析构函数(通过 delete),就需要让基类的析构函数成为虚函数,否则会产生不确定的后果。
#include <iostream>
using namespace std;
class Base{
public:
Base() {cout<<"Base constructor"<<endl;}
~Base() {cout<<"Base destructor"<<endl;}
};
class Derived:public Base{
public:
Derived() {p = new int(0);cout<<"Derived constructor"<<endl;}
~Derived() {
cout<<"Derived destructor"<<endl;
delete p;
}
private:
int *p;
};
void fun(Base* b){
delete b;
}
int main(){
Base *b=new Derived();
fun(b);
return 0;
}
结果
Base constructor
Derived constructor
Base destructor
这说明,通过基类指针删除派生类对象时调用的是基类的析构函数,派生类的析构函数没有被执行,因此派生类对象中动态分配的内存空间没有得到释放,造成了内存泄露。也就是说派生类对象成员p所指向的内存空间,在对象消失后既不能被本程序继续使用也没有被释放。对于内存需求量较大、长期连续运行程序来说,如果持续发生这样的错误是很危险的,最终将导致因内存不足而引起的程序终止。
避免上述错误的有效方法就是将基类析构函数声明为虚函数:
class Base{
public:
Base() {cout<<"Base constructor"<<endl;}
virtual ~Base() {cout<<"Base destructor"<<endl;}
};
结果
Base constructor
Derived constructor
Derived destructor
Base destructor
这说明派生类的析构函数被调用了,派生类对象中动态申请的内存空间被正确地释放这是由于使用了虚析构函数,实现了多态。