第18章 virtual

English

本章是干什么的

本章讲 new、delete、::std::unique_ptr、 virtual 和 RTTI。它们是 C++ 里被滥用得最厉害的四个特性, 也是 C++ 教程最先教的四个特性。我们在本章讲它们,只有一个理由: 你必须读遗留代码。你将来被雇去改的 C++ 代码,几乎全是用它们堆出来的。

新代码里我们不用它们,本章会用实测数据说明为什么。简版结论:

遗留特性 它真实的代价 该写什么
new / delete 手工生命周期、看不见的失败路径、失败以遗留的 ::std::bad_alloc 异常形式出现 带析构函数的拥有型类型;自己拥有存储的容器
::std::unique_ptr<T> 每个对象一次堆往返,而且这个指针在调用点说不清 T 是什么意思 值类型;当你真的需要“一个类型对应多种表示”时用类型擦除
virtual 每个对象一个指针、每个类一张表、每个虚函数不管调不调用都要生成、 __cxa_pure_virtual、RTTI、不可移植的 ABI 模板分派,或者你自己拥有的函数指针表
typeid / dynamic_cast 每个类若干 type-info 对象、被 mangle 过的名字、每次转换一次运行时搜索 什么都不用写:用了类型擦除,就没有可转换的目标
类级 operator new 分配策略藏在类型里,成对的 delete 陷阱 工厂函数,或者一个由你传进来的区域 (第18.7章)
Qt / MFC 风格 GUI 深继承层次、到处 new、整个程序绑定一个框架 ABI Web 前端 + C++ 服务端 (第21章 PWA)

这个立场来自 $HOME/libraries/Portable-Cpp-Guideline 里的规则: 避免 new、避免 ::std::unique_ptr、 多态优先用类型擦除而不是虚函数、优先用 C 风格的伪 v-table 单例而不是 C++ v-table。

为什么我们反对它们

每个特性一段话,这样本章后面就有东西可证明:

本章目录

怎么读这一章

18.1 到 18.5 当作识别训练来读:你在学的是在别人的代码里认出这些构造, 并知道每一个换来了什么、花掉了什么。18.6 是你真正要用的那一章。 18.7 只在你必须通过类型来分配内存的那天读。18.8 请在接下“Qt 开发”这份工作之前读。

这里所有规则都是关于你自己的代码的。你仍然得调用用了 virtual 的库;那没问题,fast_io 的设备层也这么做。 你不能做的是在它之上搭新的抽象。