我正在考虑在实时应用程序中使用虚拟继承。使用虚拟继承是否会产生类似于调用虚拟函数的性能影响?有问题的对象只会在启动时创建,但我担心层次结构中的所有函数都将通过 vtable 调度,或者只有来自虚拟基类的函数才会调度。
4 回答
通用实现将使对虚拟基类的数据成员的访问使用额外的间接方式。
正如詹姆斯在评论中指出的那样,在多继承场景中调用基类的成员函数将需要调整this
指针,如果该基类是虚拟的,那么基类子对象在派生类中的偏移量object 取决于派生类的动态类型,需要在运行时计算。
这是否对实际应用程序有任何明显的性能影响取决于许多因素:
虚拟基地有数据成员吗?通常,需要从虚拟派生抽象基类,而具有任何数据成员的抽象基类通常是代码异味。
假设您有带有数据成员的虚拟基地,是否在关键路径中访问?如果用户单击 GUI 中的某个按钮会导致几十个额外的间接访问,那么没人会注意到。
如果避免虚拟基地,还有什么替代方案?不仅设计可能较差,替代设计也可能对性能产生影响。毕竟,它必须实现和 TANSTAAFL 相同的目标。然后你用一种性能损失换取另一种加上劣质的设计。
附加说明:看看 Stan Lippmann 的Inside the C++ Object Model,它非常彻底地回答了这些问题。
看看下面公布的 OOPSLA'96 的大规模实验研究。我正在复制粘贴 bibtex 条目、摘要和论文链接。我认为这是迄今为止关于该主题的最全面的实验研究。
@article{driesen1996direct,
title={{The direct cost of virtual function calls in C++}},
author={Driesen, K. and H{\\"o}lzle, U.},
journal={ACM Sigplan Notices},
volume={31},
number={10},
pages={306--323},
issn={0362-1340},
year={1996},
publisher={ACM}
}
摘要: 我们研究了 C++ 程序中虚函数调用的直接成本,假设标准实现使用虚函数表。我们使用可执行检查和处理器模拟的组合,通过实验测量许多大型基准程序的这种开销。我们的结果表明,所测量的 C++ 程序的中位数为 5.2% 的时间和 3.7% 的指令用于调度代码。对于程序的“所有虚拟”版本,平均开销上升到 13.7%(占指令的 13%)。与标准实现相比,虚函数表实现的“thunk”变体将开销中位数减少了 21%。在未来的处理器上,这些开销可能会适度增加
你确定你的意思是虚拟继承?如果是这样,它与普通虚函数调用的成本相同。vtable 链式搜索只遵循指定的路径。
你说这是在启动时。您的磁盘开销(从简单地将代码加载到内存中)可能需要比六条指令多几个数量级的时间来进行 vtable 查找。如果您可以对此进行分析并发现差异,我会感到有些惊讶。
在不检查编译或运行时细节的情况下,根据我使用 GNU C++17 的测试,访问虚拟基类中的数据成员对性能没有影响。