虚析构函数的作用:
- 当直接delete子类的指针对象时,delete会先调用子类的析构函数,再调用父类的析构函数。
#include<iostream> using namespace std; class AA { public: AA(int a = 0) { this->a = a; } ~AA() { cout << "AA类的虚析构函数" << endl; } virtual void print() { cout << "AA的print()函数" << endl; } protected: int a; private: }; class BB:public AA { public: BB(int a = 0, int b = 0) { this->a = a; this->b = b; } ~BB() { cout << "BB类的虚析构函数" << endl; } virtual void print() { cout << "BB类的print()函数" << a << " " << b << endl; } protected: private: int b; }; void howToDelete(AA *pBase) { delete pBase; } void main() { BB *b1 = new BB(1, 2); b1->print(); delete b1; cout << endl; //howToDelete(b1); system("pause"); }
-
实验现象如下:
-
然而,当把子类指针传给父类指针做形参的函数,将子类指针转变为父类指针时,由于未把父类的析构函数定义为虚函数,所以此时在howToDelete()中,delete pBase;时,编译器只会执行静态联编,去调用父类对象的析构函数。而导致子类对象的析构函数并未利用C++中类指针的多态性得以调用,而无法实现子类的成员的内存释放(这也是我们要把父类中的析构函数定义成虚析构函数的目的),这没有实现动态联编。
-
将父类的析构函数定义为虚函数。
-
代码如下:
#include<iostream> using namespace std; class AA { public: AA(int a = 0) { this->a = a; } virtual ~AA() { cout << "AA类的虚析构函数" << endl; } protected: int a; private: }; class BB:public AA { public: BB(int a = 0, int b = 0) { this->a = a; this->b = b; } ~BB() { cout << "BB类的虚析构函数" << endl; } protected: private: int b; }; void howToDelete(AA *pBase) { delete pBase; } void main() { BB *b1 = new BB(1, 2); howToDelete(b1); system("pause"); }
-
运行结果如下:将基类AA的虚构函数定义为虚析构函数,在子类BB的对象传给父类指针形参pBase后,将pBase父类指针delete时,由于C++的类指针的多态特性,先释放了BB的对象的所有成员占用的的内存。之后调用父类AA类的析构函数,释放继承自AA类的成员所占用的内存(自定义AA类的析构函数,来释放AA类中的成员所占用的内存空间)。这样一来,就实现了利用C++中类指针的多态特性,使用虚析构函数先释放子类的成员占用的内存空间,再释放父类的成员所占用的内存。
-
简而言之,虚析构函数,还是利用了C++类指针的多态特性,使得父类指针根据其指向的具体对象(父类或子类),来调用相应的父类(先子类后父类)的析构函数,来实现多态(动态联编)。使得子类中的自定义成员得以释放,以免未调用子类的析构函数,造成内存泄漏。