正面回答:
当基类的析构函数不是虚函数,并且基类指针指向一个派生类对象,然后通过基类指针来删除这个派生类对象时,如果基类的析构函数不是虚析构函数,那么派生类的析构函数就不会被调用,从而产生内存泄漏
#include#include using namespace std; class A { public: A() { cout<<"constructing A"<<endl; } ~A() { delete p; cout<<"destructing A"<<endl; } private: int *p; }; class B:public A { public: B() { cout<<"constructing B"<<endl; } ~B() { delete p; cout<<"destructing B"<<endl; } private: int *p; }; int main() { A *a=new B(); delete a; } /* constructing A constructing B destructing A */
分析:只调用了基类A的析构函数,而派生类B的析构函数却没有被调用,这时会产生内存泄漏
如果给基类A的析构函数是虚析构函数,那么便不会产生这个问题
#include#include using namespace std; class A { public: A() { cout<<"constructing A"<<endl; } virtual ~A() { delete p; cout<<"destructing A"<<endl; } private: int *p; }; class B:public A { public: B() { cout<<"constructing B"<<endl; } ~B() { delete p; cout<<"destructing B"<<endl; } private: int *p; }; int main() { A *a=new B(); delete a; } /* constructing A constructing B destructing B destructing A */
此时派生类B的析构函数被调用了!内存泄漏的问题得以解决
注意构造函数和析构函数的执行顺序:
派生类构造时:先执行基类的构造函数,然后执行派生类的构造函数
派生类析构时:先执行派生类的析构函数,然后执行基类的析构函数
上面内存泄漏产生的必要条件:
1.基类析构函数不是虚析构函数
2.派生类对象的析构函数中有内存需要回收
3.基类指针指向派生类对象,通过删除该基类指针来删除派生类对象
那这种情况下为什么会产生内存泄漏呢?
这种情况下,当删除基类指针指向的派生类对象时不会触发动态绑定,虚函数是动态绑定的基础,现在基类的析构函数不是虚函数,所以不会发生动态绑定,而是静态绑定,指针的静态类型为基类类型,所以delete的时候只会调用基类的析构函数
结论:
人生建议,继承时,基类的析构函数中最好加上virtual。