【C++ Efficiency】理解虚函数、多重继承、虚基类和RTTI

虚函数

虚函数的实现

当调用一个虚函数时,一般都是使用了virtual table和virtual table pointer,简称vtbl和vptr:

vtbl

一个函数指针数组。

在程序中,一个类凡是声明或继承了虚函数,都有一个vtbl,是指向虚函数实现体的指针。例如:

cpp 复制代码
class C1
{
public:
	C1();
	virtual ~C1();
	virtual void f1();
	virtual int f2(char c) const;
	virtual void f3(const string& s);
	void f4() const;
	...
};
//虚函数按照其声明顺序放于vtbl表中
//vtbl数组中的每一个元素对应一个函数指针指向该类的虚函数
cpp 复制代码
//如果C2继承自C1,重新定义某些继承而来的虚函数,并加入新的虚函数:
class C2 : public C1
{
public:
	C2();						//非虚函数
	virtual ~C2();				//重定义函数
	virtual void f1();			//重定义函数
	virtual void f5(char* str);	//新的虚函数
	...
};
//此时,C2的vtbl包括没有被C2重定义的C1虚函数的指针f2、f3

vptr

凡是声明了虚函数的类的对象都含有一个隐藏的数据成员,指向对应的类的virtual table,称为vptr。

虚函数的调用

  1. 通过对象的 vptr 找到类的 vtbl。这是一个简单的操作,因为编译器知道在对象内 哪里能找到 vptr(毕竟是由编译器放置的它们)。因此这个代价只是一个偏移调整(以得到 vptr)和一个指针的间接寻址(以得到 vtbl)。
  2. 找到对应 vtbl 内的指向被调用函数的指针。这也是很简单的, 因为编译器为每个虚函数在 vtbl 内分配了一个唯一的索引。这步的代价只是在 vtbl 数组内 的一个偏移。
  3. 调用第二步找到的的指针所指向的函数。

虚函数的成本

  1. 虚函数的第一个成本:

    你必须为每个拥有虚函数的类耗费一个virtual table空间,其大小视虚函数的个数而定,包括继承而来的。

  2. 虚函数的第二个成本:

    你必须在每一个拥有虚函数的对象内付出"一个额外指针"的代价。

  3. 虚函数的第三个成本:

    你放弃了使用内联函数。

参考:C++虚函数实现原理与代价

多重继承

每个对象含有多个vptr,针对不同的父类vtbl,子类产生一个特殊的vtbl。

虚基类

D->B->A,D->C->A,会导致A的字段在D中有两份,这显然不合理。为了解决这个问题,使用虚拟继承:B,C虚继承A,大多数编译器会利用这样的机会来减少编译器的负担。。

运行时类型识别RTTI

  • C++提供关键字typeid 获取类的type_info对象;
  • 一个类对应于一个type_info对象;
  • 类及其所有的对象共享一份RTTI信息。

RTTI的设计理念是:根据class的vtbl来实现。

总结

理解虚函数、多重继承、虚基类及RTTI的成本很重要。

但你必须知道:如果你需要这些功能,就要忍受这些成本,世事难两全。有时你确实想要回避编译器生成的服务,例如隐式vptr和"指向虚基类"的指针会造成"将C++对象存储于数据库"和"跨进程移动C++对象"困难度提高,所以你希望有某种方法模拟这些性质。不过从效率上来讲,自己写的不可能比编译器生成的更好。

相关推荐
王老师青少年编程5 小时前
信奥赛C++提高组csp-s之搜索进阶(搜索剪枝案例实践1)
c++·csp·高频考点·信奥赛·提高组·搜索剪枝·小木棍
石山代码6 小时前
ArrayList / HashMap / ConcurrentHashMap
java·开发语言
程序大视界6 小时前
【Python系列课程】Python正则表达式(下):环视、命名分组与日志实战
开发语言·python·正则表达式
枫叶v.7 小时前
Agent 分层存储架构设计:从记忆方法到中间件选型
开发语言·python
sleven fung8 小时前
MinerU与BabelDOC与KTransformers与OpenAI API库
开发语言·python·ai·langchain
AOwhisky8 小时前
Ceph系列第六期:Ceph 文件系统(CephFS)精讲
linux·运维·网络·笔记·ceph
萤萤七悬8 小时前
【Python笔记】AI帮实现CLI工具-使用argparse.ArgumentParser接收命令参数
开发语言·笔记·python
iCxhust8 小时前
C# 命令行指令 查看二进制文件
开发语言·单片机·嵌入式硬件·c#·proteus·微机原理·8088单板机
csdn_aspnet8 小时前
Java 霍尔分区算法(Hoare‘s Partition Algorithm)
java·开发语言·算法
王老师青少年编程8 小时前
信奥赛C++提高组csp-s之搜索进阶(搜索剪枝核心思想 )
c++·dfs·csp·信奥赛·搜索剪枝·搜索优化