原则24:理解虚拟函数、多继承、虚基类和RTTI所需的代价

C++中存在一个虚函数的概念,每个类维持了一个虚表,这个虚表需要占用空间。在程序连接之前会有很多对象文件,怎样为这些对象文件分配虚表,编译器厂商提出了两种解决方案。
1、整个程序的要经过编辑、编译、连接和执行四个阶段,其中连接是指连接在编译阶段生成的对象文件。在连接前为每个对象文件生成一个虚表,连接以后去掉重复的虚表,最后在可执行文件里只保留一份虚表。
2、只有某对象文件包含该类的第一个非inline,非纯虚拟函数的虚拟函数定义才给该对象一份虚表,而这个第一是指在类的声明式中的顺序。
虚拟机制决定你还要为虚拟指针付出开销。每个涉及到虚拟机制的对象都包含一个指向类的虚表的虚拟指针,这会为对象造成额外的开销。这意味着在空间一定的条件下,你能建立的对象比你预期的要少。另外,较大的对象不适合放在缓存里面,也不适合放在虚拟内存页当中,因为这会增加操作系统换页操作次数。
虚拟函数是不能被内联的。因为内联发生在编译期,动态绑定发生在运行期。所以一旦使用了虚拟函数,你就放弃了内联函数带来的便利。
在多继承的情况下,每个对象会为每个基类生成一个虚指针和虚表,所以虚拟机制在多继承的情况下开销更大。
下面是虚拟继承的示意图:


原则24:理解虚拟函数、多继承、虚基类和RTTI所需的代价_第1张图片

作者说D会把A放在自己下面,而BC如常地在D上面。书中说BD能共享同一个虚指针,但没说为啥能共享,难道是从继承层次上来说的?这个我不清楚。不过我想可能是因为D把A放在下面了,所以A的虚指针应该可以供D使用吧。
RTTI也是在运行时判断类型的,它是通过在虚表的第一项上添加type_info来实现的,所以它和虚拟继承是有必然联系的。所以它也需要额外开销。
本原则旨在说明,你不要妄想自己编代码代替这些已有的功能,因为你编的代码很难有这些机制高效、正确、实用。所以你更多的时候不应该想着如何去替换这些东西而是多多理解如何去运用。

多谢捧场

如果您觉得我的文章有价值,那么赏脸打赏一个,鄙人感激不尽。不过,不打赏看看也是好的,如果有不对的地方,还请您多多指正。


你可能感兴趣的:(原则24:理解虚拟函数、多继承、虚基类和RTTI所需的代价)