欢迎光临散文网 会员登陆 & 注册

Effective C++ 第七条 Declare destructors virtual in polymorphic bas

2023-01-10 07:58 作者:九思519  | 我要投稿

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

考虑一个情况,就是我们当前有一个目标功能,就是时间操作,但是有多种方法可以尝试,比如原子钟、水钟、腕表等

注意,这里的析构函数是non-virtual的,原则上来说不适合作为基类(base-class),不适合用于作为继承的父类,原因需要考虑到以下场景

程序运行也许不会出错,但是有一些问题会导致内存泄漏,比如当客户使用完需要释放空间的时候,delete ptr;并不难完全释放空间,因为这里我们想使用类的多态性质,通告一个TimeKeeper(base)去实现多种子类(derived),然而TimeKeeper型指针在构造的时候只会初始化属于TimeKeeper的内容,不会初始化AtomicClock里的成员(这一点暂且记住,不是本章重点)。更重要的是,TimeKeeper的析构函数并不会去释放子类中的空间,只会释放属于TimeKeeper类中的 __i_T;管不了子类中的 __i_AC;这一点可能导致很严重的空间浪费。于是我们采取父类使用虚析构函数(关于 vtbl 和 vptr 的详细内容放到本章末尾,如果不懂可以先看完末尾讲解再回到当前位置继续阅读)

采用了虚析构函数之后,delete ptr;便会调用子类的析构函数了,便不需要担心子类的成员无法释放。但是也不建议无脑用virtual,如果一个类设计出来便是为了做父类的就建议使用虚析构函数,因为你每使用一个虚函数会多使用一个虚函数指针,每个指针占据 8 字节(在64位操作系统下),如果使用了很多虚函数但是却没有实际用处,会浪费空间,不利于cache命中,降低程序运行速度。

vptr 和 vtbl 的作用

virtual table pointer 和 virtual table 是为了实现多态而出现的,下面给出一个实例

此时输出为 A A A ,a2和a3是B1和B2类,但是仍绑定的A的op

如果给A中的op加上virtual

此时输出结果是 A B1 B2,也就是说实现了多态,这样的好处是,用户在使用功能的时候不需要区分清楚A、B1、B2的区别,我们可以把A看作初始版本,B1、B2看作迭代版本,无论版本迭代多少次,用户只需要按照最初的操作即可完成任务。后续的布丁只需如此


Effective C++ 第七条 Declare destructors virtual in polymorphic bas的评论 (共 条)

分享到微博请遵守国家法律