16 More Effective C++ —— 条款23/24 (虚函数、虚基类、多继承、RTTI)

0 前序

由于条款23只是针对iostream和stdio.h之间,进行运行效率的对比,此处不会详细展开。其宗旨是尽量使用C++的库,可以提高程序的执行效率和安全性。

此篇将着重讨论条论24的内容。

1 多态

C++中,多态是指使用基类指针、引用指向派生类,若基类和派生类中,有签名完全相同的函数,则指针或者引用会根据实际指向的对象,来进行相应的调用。具体使用如下。

class  BaseClass
{
	public:
		virtual void do();
}
class DeriveClass : public BaseClass
{
	public:
		virtual void do();
}
BaseClass* base = new DeriveClass;
base->do(); //此时调用派生类的do()

2 虚函数的成本

成本1:维护的virtual table

多数编译器使用virtual table,或者virtual table pointer来指向相应的映射表。这种表通常由一个函数指针指向数组,编译期间再转换成“链表”,由类自身维护。

通常,会将这个virtual table存放在下面两个地方。

1 对于提供整合环境(编译器和链接器),每一个需要的目标文件,都提供一个virtual table的记录。再有连接器剥除重复的副本。使最终可执行的程序,或库内,只留下一个vtbl。
2 以探测式的方式来决定,那个文件存储哪个vtbl。类的vtbl放置于第一个non-inline, non-pure的虚函数定义文件中,即第一次定义虚函数的cpp文件中。
此种方法的前提是,虚函数不能为Inline,否则在每个inline处,都会由一个函数副本。目前,编译器都会直接忽略虚函数的inline修饰。

成本2:对象维护的指针

此外,不仅每个class内维护一个vtbl,每个类对象中,也需要维护一个指向该类vtbl的指针,用于标识该对象真正所属的类型。

当我们通过基类指针,调用虚函数的时候,首先,通过vptr找到当前对象,指向的class的vtable,再用函数的index直接调用函数即可。这样调用,开销和非虚函数调用开销基本相当。

成本3:放弃inline的虚函数

但是,若虚函数被声明为inline,则会出现下面的矛盾。

虚函数是运行期的功能,virtual意味着等待,知道程序在运行状态下,才能决定被函数。而inline是编译期的功能,其加速了程序的调用。

两种技术所应用的时期不同,因此,虚函数即意味着去掉了inline。

扫描二维码关注公众号,回复: 4660860 查看本文章

成本4:运行时期类型识别成本(runtime type identification)

对象的类型被存放在type_info的结构中,使用typeid操作符,可以获得type_info结构。该结构进一步描述了对象和类所具有的运行时特征。

猜你喜欢

转载自blog.csdn.net/zhizifengxiang/article/details/85128947