当我们采用如下方式直接定义一个子类的对象的时候,我们知道由于子类继承于基类,所以在main函数结束返回时,程序会先调用子类的析构函数,再调用基类的析构函数。
int main() { SubClass c; return 0; }
但为了实现C++的多态,我们经常要用一个基类的指针指向一个子类的数据:
BaseClass *c = new SubClass;
这时编译器会认为指针是基类的,因此在我们释放指针时,程序就不会运行子类的析构函数,而只运行了基类的析构函数。而如果在子类的析构函数中存在着重要的释放内存的操作,那么此时就会导致内存泄漏问题。
以如下代码作为实验代码来看看如果我们不将基类的析构函数定义为虚方法会产生什么结果:
#include <iostream> using namespace std; class BaseClass { public: BaseClass() { }; ~BaseClass() { cout << "In ~BaseClass" << endl; }; }; class SubClass : public BaseClass { public: SubClass() { }; ~SubClass() { cout << "In ~subclass" << endl; }; }; int main() { BaseClass *c = new SubClass; delete c; return 0; }
运行结果:
In ~BaseClass
可以看到,程序只打印了基类的析构函数中的内容,也就是程序没有运行子类的析构函数。
将基类析构函数定义为虚方法
将函数定义为虚方法,是为了告诉编译器,要根据运行时候的指针的类型而有选择地调用正确的方法,而new分配内存给指针的方式,指针只有在运行时候才是子类,因此将基类的析构器定义为虚方法:
virtual ~BaseClass()
就能让程序在释放指针时运行子类的析构函数。
修改代码如下:
#include <iostream> using namespace std; class BaseClass { public: BaseClass() { }; virtual ~BaseClass() { cout << "In ~BaseClass" << endl; }; }; class SubClass : public BaseClass { public: SubClass() { }; ~SubClass() { cout << "In ~subclass" << endl; }; }; int main() { BaseClass *c = new SubClass; delete c; return 0; }
程序运行结果:
In ~subclass In ~BaseClass
此时在析构时,程序能够运行子类和基类的析构函数。