虚函数的成本是不是会随着继承树中类的数量而增加?

Posted

技术标签:

【中文标题】虚函数的成本是不是会随着继承树中类的数量而增加?【英文标题】:Does the cost of virtual functions increase with the number of classes in the inheritance tree?虚函数的成本是否会随着继承树中类的数量而增加? 【发布时间】:2013-08-23 00:07:12 【问题描述】:

正如标题所说,例如拥有 8 个带有虚函数的派生类比拥有 2 个派生类对性能的影响更大吗?如果是这样,差异可以忽略不计吗?

那么多重继承(非虚拟继承)呢?

提前致谢。

【问题讨论】:

唯一的“成本”是每个对象的 vtable 的大小,但就性能而言,它应该没有任何区别,因为一旦 vtable 被初始化,它只是一个简单的数组查找。跨度> 我确实认为它通常是实现的,所以继承的数量没有任何损失。 【参考方案1】:

在 C++ 中动态调度的常见实现是通过一个虚拟表来实现的,它基本上是一个指向函数的指针数组,一个指向类型中的每个虚拟函数的指针。继承链的长度无关紧要,因为 vtable 只保存一个指针,即完整对象中该特定函数的最终覆盖器的指针。无论最终的覆盖器是在基础还是一百级,这将是一个单一的间接。

多重继承对性能的影响很小,影响程度取决于实际实现,但与基数无关。在单继承的情况下,基对象和派生对象在内存中对齐,指向派生类型的指针的值将与转换为指向基类型的指针的同一指针具有相同的地址。在多重继承的情况下(假设基不为空),情况并非如此。只有第一个 base[*] 可以与整个对象对齐。

缺乏对齐的含义是this指针将需要调整以指向适当的位置,这取决于哪个是完整对象中虚函数的最终覆盖者。一个简单的实现可以将偏移量和指向函数的指针都存储在 vtable 中,使用偏移量来调整指针,然后跳转到函数。这意味着每次调用虚函数时都会向this 指针添加(可能为0)。在现实生活中,编译器通常存储一个指向函数的指针,如果不需要调整 this 指针,该函数将引用最终覆盖器,或者存储一个小的蹦床函数,该函数将偏移 this 指针并转发到该函数覆盖者。

您明确提到您对虚拟继承并不真正感兴趣,我将跳过复杂的进一步解释。以上所有内容已经有点简化了,但希望您能理解。继承链的高度无关紧要,宽度可能会产生非常小的影响(额外的跳转和添加,或一些类似的成本,具体取决于实现。

如果您有兴趣,我建议您阅读 Lippman 的C++ 对象模型。即使这本书已经超过 15 年了,并且包含错​​别字等,它也描述了在实现对象模型和 cmet 中的一些解决方案中的许多问题。

[*] 使用空基优化,这将成为所有空基第一个非空基。

【讨论】:

以上是关于虚函数的成本是不是会随着继承树中类的数量而增加?的主要内容,如果未能解决你的问题,请参考以下文章

空类,含有虚函数的类的大小

C++中,子类会继承父类的虚函数表!对于父类的析构函数(虚函数) 也会继承吗?

基本语言

C++ ——虚继承时的构造函数

C++ ——虚继承时的构造函数

C++中的虚函数(类的向上转换,和向下转换)