1. 虚析构函数与纯虚析构函数
1.1 虚析构函数与纯虚析构函数的定义
- 虚析构函数:为了解决基类的指针指向派生类对象,并用基类的指针删除派生类对象;
虚析构函数:当且仅当类里包含至少一个虚函数的时候才去声明虚析构函数,无故的声明虚析构函数和永远不去声明一样是错误的;
class <类名> { virtual ~<类名>(); … }; 即:virtual ~A();
纯虚析构函数:抽象类是准备被用做基类的,基类必须要有一个虚析构函数,纯虚函数会产生抽象类,所以方法很简单,在想要成为抽象类的类里声明一个纯虚析构函数;
class <类名> { virtual ~<类名>() = 0; … }; 即:virtual ~A() = 0;
注:如果某个类不包含虚函数,那一般是表示它将不作为一个基类来使用。当一个类不准备作为基类使用时,使析构函数为虚一般是个坏主意。因为它会为类增加一个虚函数表,使得对象的体积翻倍,还有可能降低其可移植性。
1.2 带有虚函数功能的类需要一个虚析构函数的原因
- 如果一个类有虚函数功能,它经常作为一个基类使用;
- 如果它是一个基类,它的派生类经常使用new来分配;
- 如果一个派生类对象使用new来分配,并且通过一个指向它的基类的指针来控制,那么它经常通过一个指向它的基类的指针来删除它;
注:
(1)如果基类没有虚析构函数,结果将是不确定的,实际发生时,派生类的析构函数永远不会被调用。
(2)如果基类有虚析构函数的话,最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。
1.3 虚析构函数的注意点
- 由于析构函数不允许有参数,因此它不可能实现重载,那么一个类就只能有一个虚析构函数;
- 只要基类的析构函数被声明为虚函数,则派生类的析构函数无论说明与否,都自然是析构函数;
- 如果基类中定义了虚函数,析构函数也应说明为虚函数,这样对内存的回收更准确些;
注:在C++中虚构造函数是不存在的,因此也无法声明。
1.4 虚析构函数的实例
(1)在带有虚函数的基类中定义普通析构函数
#include <iostream> using namespace std; class A { public: A(){cout<<"A()..."<<endl;} ~A(){cout<<"~A()..."<<endl;} public: virtual void func1() { cout<<"A::func1()"<<endl; } }; class B : public A { public: B(){cout<<"B()..."<<endl;} ~B(){cout<<"~B()..."<<endl;} public: virtual void func1() { cout<<"B::func1()"<<endl; } }; int main() { A *pb = new B; pb->func1(); delete pb; system("pause"); return 0; } =>A()... B()... B::func1() ~A()... 注:派生类继承自基类,那么基类就只会存在于派生类中,直到派生类调用析构函数后。 当上述这种情况,基类的析构函数调用比派生类要早,会造成的一种情况就是类成员不存在了,而类本身却还在,但是类存在的情况下,类成员应该还存在。所以这就矛盾了,应该派生类的析构函数会先被调用,基类的析构函数再被调用。
(2)在带有虚函数的基类中定义虚析构函数
#include <iostream> using namespace std; class A { public: A(){cout<<"A()..."<<endl;} virtual ~A(){cout<<"virtual ~A()..."<<endl;} public: virtual void func1() { cout<<"A::func1()"<<endl; } }; class B : public A { public: B(){cout<<"B()..."<<endl;} virtual ~B(){cout<<"virtual ~B()..."<<endl;} public: virtual void func1() { cout<<"B::func1()"<<endl; } }; int main() { A *pb = new B; pb->func1(); delete pb; system("pause"); return 0; } =>A()... B()... B::func1() virtual ~B()... virtual ~A()...
注:析构函数的作用并不是删除对象,而是撤销对象占用内存之前完成的一些清理工作。
(1)抽象类是准备被用做基类的,基类必须要有一个虚析构函数,纯虚函数会产生抽象类,所以在想要成为抽象类的类里声明一个纯虚析构函数。
(2)定义一个函数为虚函数,不代表该函数未被实现,只是为了来实现多态。
(3)定义一个函数为纯虚函数,才表示函数未被实现 ,定义它是为了实现一个接口,起一个规范作用。继承抽象类的派生类要实现这个函数。
参考文献:
[1]《C++全方位学习》范磊——第十三章
[2]《C++程序设计教程(第二版)》钱能——第五章、第六章、第七章
[3]《C++ Primer(第5版)》王刚 杨巨峰——第一章、第六章
[4] 百度搜索关键字:C++函数、虚析构函数、纯虚析构函数