effective_为多态基类声明虚析构函数

条款07这里需要补充的知识点(我觉得很重要):

一.如果一个类不企图被当作基类,那么令其析构函数为虚函数是很愚蠢的。正确的做法应该是:只有当类中有至少一个虚函数时,才把其析构函数声明为虚析构函数。

因为虚函数的作用是为了动态联编(实现多态),而为了实现动态联编,对象需要额外多出vptr指针,会增加体积(sizeof可以明显看出),vptr指向一个由函数指针构成的数组,称为vtbl(虚表),每一个带有虚函数的类都有一个相应的vtbl,实际被调用的函数取决于该对象的vptr所指的那个vtbl。(vptr的分步初始化知识点见笔记)

二.有时我们希望拥有抽象类,但手上又没有任何纯虚函数,怎么办?

1.由于抽象类总是被企图当作一个基类,又由于多态基类为了防止内存泄漏,应该有个虚析构函数,因此,解决办法就是为这个抽象类声明一个纯虚析构函数
2.但又因为派生类对象析构时需要调用抽象类(基类)的析构函数(回顾一下析构函数的运作方式:最远的派生类的析构函数最先被调用,然后是各个基类的析构函数被调用,和构造函数的调用顺序恰好相反),而抽象类的纯虚构函数是没有函数体的,这样就会报错。所以解决办法是在抽象类的类外实现其函数体,而不是在派生类中重写,这是纯虚析构函数和其它纯虚函数相比的特殊之处。(详见下文“纯虚函数也可以有函数体”);

例子如下:

#include<iostream>
using namespace std;
class Base {//抽象类
public:
	virtual ~Base() = 0;//纯虚析构函数
};
Base::~Base() { cout << "Base destructor" << endl; }//纯虚函数也可以有函数体

class Derive :public Base {
public:
	~Derive() { cout << "Derive destructor" << endl; }//派生类的析构函数,是虚函数(省略virtual)!

};

int main() {
	Base *pb = new Derive();//在堆内存上new一个派生类的对象,然后使基类指针指向派生类的对象
	delete pb;
	system("pause");
	return 0;
}

在这里插入图片描述

三.纯虚函数也可以有函数体,但是一般没必要这样做,纯虚函数添加函数体,依旧为纯虚函数,类依旧是抽象类,不能实例化

发布了146 篇原创文章 · 获赞 3 · 访问量 4982

猜你喜欢

转载自blog.csdn.net/ShenHang_/article/details/103746609