侧边栏壁纸
博主头像
如此肤浅

但行好事,莫问前程!

  • 累计撰写 52 篇文章
  • 累计创建 6 个标签
  • 累计收到 6 条评论

目 录CONTENT

文章目录

条款07 为多态基类声明 virtual 析构函数

如此肤浅
2022-05-14 / 0 评论 / 0 点赞 / 42 阅读 / 1,173 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-15,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1. 带多态性质的 base classes 应该声明一个 virtual 析构函数。如果 class 带有任何 virtual 函数,它就应该拥有一个 virtual 析构函数;
2. Classes 的设计目的如果不是作为 base classes 使用,或不是为了具备多态性,就不该声明 virtual 析构函数。

class Animal {
public:
	Animal();
	~Aimal();
    ...
};

class Dog: public Animal { ... };

class Cat::public Animal { ... };
Animal* pta = new Cat();	// 在堆区开辟内存
...
delete pta;	// 释放内存

上面代码的问题是,由于基类中的析构函数是非虚(non-virtual)析构函数,在 delete 释放内存的时候只调用了基类的析构函数,而不会调用其派生类的析构函数,导致内存泄露!

解决方式是给基类一个 virtual 析构函数:

class Animal {
public:
	Animal();
	virtual ~Aimal();
    ...
};

不能无脑地将所有类的析构函数都声明为 virtual

虚函数实现原理: 若某个类声明了 virtual 函数,则对象携带某些信息,用来在运行期决定哪一个 virtual 函数该被调用。这份信息通常是由一个所谓 vptr ( virtual table pointer)指针指出。vptr 指向一个由函数指针构成的数组,称为 vtbl(virtual table);每一个带有 virtual 函数的 class 都有一个相应的 vtbl。当对象调用某一 virtual 函数,实际被调用的函数取决于该对象的 vptr 所指的那个 vtbl,编译器在其中寻找适当的函数指针。

由虚函数实现原理可知,若某个类声明了虚函数,则对象会占用更多的内存,有时可能因为这些增加的内存导致该对象无法放入缓存器中,导致运行速度变慢。

因此,只有当 class 内含至少一个 virtual 函数,才为它声明 virtual 析构函数。

使用纯虚函数避免内存泄露

某个类只要有纯虚函数,则该类无法被实体化。即,该类变为 abstract(抽象)类,也就是说,无法为这个类创建对象。

class AWOV {
public:
	virtual ~AWOV() = 0;	// 声明纯虚析构函数
}
// 必须提供一个纯虚析构函数的定义
AWOV::~AWOV() { }

这个类有一个 pure virtual 函数,所以它是个抽象class,又由于它有个 virtual 析构函数,所以你不需要担心上述析构函数的内存泄露问题。

析构函数的运作方式是,最深层派生的那个类的析构函数最先被调用,然后是其每一个基类的析构函数被调用。

再次强调: “给基类一个虚析构函数”,这个规则只适用于带多态性质的基类身上。这种基类的设计目的是为了用来“通过基类接口处理派生对象”。

并非所有基类的设计目的都是为了多态!!!

0

评论区