虚析构函数

 还是一篇有关虚函数的文章,这次是解析虚析构函数的。先直接上代码吧。 #include <iostream> using namespace std; class A { public: int a; A() { cout<<"A"<<endl; } ~A(){ cout<<"~A"<<endl; } } class B { public: A *pA; B() { pA = new A(); cout<<"B"<<endl; } virtual ~B() { delete pA; cout<<"~B"<<endl; } } class C : public B { public: C():B() { cout<<"C"<<endl; } ~C() { cout<<"~C"<<endl; } } int main() { B* pB = new C; delete pB; return 0; }
运行结果:若19行没有virtual:A   B   C  ~A  ~B
                若19行有virtual:    A   B   C  ~C  ~A  ~B
这个结果说明,如果类B被类C继承,而且用父类的指针指向其子类对象(比如:B *bB = new C;)时,那么父类B的析构函数必须是虚的,否则在delete bB的时候,只会调用父类B的析构函数,子类C的析构函数不会被调用。这样会造成内存泄露。

构造函数的工作方式:先调用父类的构造函数,再调用派生类的构造函数。
析构函数的工作方式:先调用派生类的析构函数,再调用每一个父类的析构函数。

如果层次中根类的析构函数是虚函数,则派生类的虚构函数也将是虚函数 ,无论派生类显式定义析构函数还是使用合成析构函数,派生类的析构函数都是虚函数。这样就说明了下面的问题,因为B的析构函数是虚函数,那么C的虚构函数也是虚函数,这样,~B和~C都存在于C的虚表之中,在B *pB = new C;的时候,将C的虚表浅拷贝到了B类指针指向的区域,那么在delete pB;的时候,自然会调用到
~C和 ~B。

虚析构函数_第1张图片
从上面这张图片可以看出,在B *pB = new C;这一步时,C对象的虚函数表被浅拷贝到B对象的虚函数表 。从而delete pB;的时候,调用了C的析构函数。

后来还遇到一种情况,如下:
class CA { public: CA(){cout<<"CA constructor"<<endl;} ~CA(){cout<<"CA desstructor"<<endl;} }; class CB:public CA { public: CB(){cout<<"CB constructor"<<endl;} ~CB(){cout<<"CB desstructor"<<endl;} }; class CC:public CB { public: CC(){cout<<"CC constructor"<<endl;} ~CC(){cout<<"CC desstructor"<<endl;} }; 主函数为:int main() { CA * p = new CC(); delete p; return 0; } 的时候,输出的结果如下:
CA constructor
CB constructor
CC constructor
这种情况是,没有调用析构函数,直接把申请的内存给释放了。

你可能感兴趣的:(虚析构函数)