虚析构函数-C++复习三
引出问题
通常,我们在类的析构函数中删除一些在堆上申请的内存,以释放不断增长的内存空间.虚函数声明语法如下:
~type_name();
假设有个类child,从base类派生而来,并且child类使用多态技术实现了方法func, 同时child包含了一个char指针成员,在child的构造函数中使用new操作符创建该成员变量,代码如下:
class base
{
public:
base()
{
cout<<"base constructor invoked"<<endl;
}
~base()
{
cout<<"base destructor invoked"<<endl;
}
virtual void func()
{
cout<<"base func invoked"<<endl;
}
private:
};
class child : public base
{
public:
child()
{
cout<<"child constructor invoked"<<endl;
m_pBuf = new char[1024];
}
~child()
{
cout<<"child destructor invoked"<<endl;
delete []m_pBuf;
}
virtual void func()
{
cout<<"child func invoked"<<endl;
}
private:
char *m_pBuf;
};
int main()
{
{
base *pObj = new child();
pObj->func();
delete pObj;
}
return 0;
}
输出如下:
程序说明:
在main中,我们创建了派生类child的对象,并让基类base的指针指向它,以达到多态的目的,当我们不需要这个对象时,使用delete操作符将pObj删除,但是,pObj对象销毁时,并没有调用child类的析构函数,只是调用了基类的析构函数.从而导致了派生类成员m_pBuf不能删除,发生了内存泄露.
当然有些友好的编译器可能会发出警告,指出基类没有将析构函数声明为virtual的害处,如:
=== Build: Debug in virtualdestructor (compiler: GNU GCC Compiler) ===|
/root/projects/cpp/virtualdestructor/main.cpp||In function ‘int main()’:|
/root/projects/cpp/virtualdestructor/main.cpp|51|warning: deleting object of polymorphic class type ‘base’ which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]|
分析
在C++中,new 和 delete对象的类型必须一致,而这个规定对类派生却是意外,允许delete指向派生类对象的基类指针.
但是,调用的是基类的析构函数,除非我们将基类的析构函数声明为virtual,否则派生类的析构函数将不会被调用.也就是说,只有将基类的析构函数声明为virtual,程序才能按正确的顺序执行析构函数(先执行派生类的析构函数,再执行基类的析构函数).
解决办法
将基类的虚函数声明为virtual,如
virtual ~base();
结论
在实现类时,总是将类的析构函数声明为虚函数是有益处的,如果类没有被派生,也没有什么害处.而如果有派生类,就有可能发生内存泄露!