为什么析构函数必须是虚函数?

为实现多态性,可以通过基类的指针或引用访问派生类的成员。也就是说,声明一个基类指针,这个基类指针可以指向派生类对象

用派生类的实例去初始化基类指针,随后删除这个指针,会导致只有基类的析构函数被调用

当基类的析构函数被定义成虚函数时,我们再来删除这个指针时,先调用派生类的析构函数,再调用基类的析构函数,很明显这才是我们想要的结果。因为指针指向的是一个派生类实例,我们销毁这个实例时,肯定是希望即清理派生类自己的资源,同时又清理从基类继承过来的资源。而当基类的析构函数为非虚函数时,删除一个基类指针指向的派生类实例时,只清理了派生类从基类继承过来的资源,而派生类自己独有的资源却没有被清理,这显然不是我们希望的。

为什么默认的析构函数不是虚函数?

虚函数不同于普通成员函数,当类中有虚成员函数时,类会自动进行一些额外工作。这些额外的工作包括生成虚函数表和虚表指针,虚表指针指向虚函数表。每个类都有自己的虚函数表,虚函数表的作用就是保存本类中虚函数的地址,我们可以把虚函数表形象地看成一个数组,这个数组的每个元素存放的就是各个虚函数的地址。

这样一来,就会占用额外的内存,当们定义的类不被其他类继承时,这种内存开销无疑是浪费的。

当我们创建一个类时,系统默认我们不会将该类作为基类,所以就将默认的析构函数定义成非虚函数,这样就不会占用额外的内存空间。同时,系统也相信程序开发者在定义一个基类时,会显示地将基类的析构函数定义成虚函数,此时该类才会维护虚函数表和虚表指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

using namespace std;

class Father {
public:
virtual ~Father() { // √ 显示地定义成虚函数
cout << "class Father destroyed" << endl;
}
};

class Son : public Father {
public:
// 基类和派生类的析构函数都会调用
~Son() {
cout << "class Son destroyed" << endl;
}
};

int main() {
Father* p = new Son;
delete p;

return 0;
}

析构函数使用 override

子类可以在其析构函数后增加关键字override,一旦父类缺少关键字virtual就会被编译器发现并报错。

参考:https://blog.csdn.net/qq_42247231/article/details/105109709