为什么C++虚拟调用并不比非虚拟调用慢?

CPW*_*CPW 5 c++ performance

在我的理解中,对于C++虚拟调用,它需要:

  1. 从符号表中获取对象的类型
  2. 从类型表中获取v表
  3. 使用v表中的函数签名搜索函数
  4. 调用该函数.

而对于非虚拟(例如在C)呼叫,仅需要#4.

我认为#3应该是最耗时的.鉴于C++中实时覆盖的性质,我看不到上述步骤的编译时间优化的可能性.因此,对于具有长函数签名的复杂类继承,C++虚拟调用应该比非虚拟调用慢得多.

但所有的说法都是相反的,为什么?

Nic*_*las 7

  1. 从符号表中获取对象的类型
  2. 从类型表中获取v表
  3. 使用v表中的函数签名搜索函数
  4. 调用该函数.

这对基于v-table的调度如何工作的理解很差.它更简单:

  1. 从对象指针获取v表.为相关函数选择正确的v表(如果使用了多个基类).
  2. 将确定的编译时间的特定偏移量添加到此v表指针,从而获取特定的函数指针.
  3. 调用该函数指针.

每个对象都有一个v表指针,该指针指向该对象原始类型的v表.所以不需要从"符号表"中获取类型.不需要搜索v表.根据编译时提供的函数签名,编译时可以确切地确定需要访问v表中的哪个指针.这完全是关于编译器如何索引类中的每个虚函数.它可以确定每个虚函数的特定顺序,因此当编译器调用它时,它可以确定要调用的函数.

所以它整体来说非常快.

处理虚拟基类时,它有点复杂,但总体思路仍然相同.

  • 在处理多个基类时,它也有点(但只是一点点)更复杂(因为在这种情况下,至少可能有两个(或更多)vtable指针,每个基类一个. (2认同)

Alo*_*ave 4

与普通函数调用相比,虚拟函数调用的开销是两个额外fetch操作(一个用于获取 v 指针的值,第二个用于获取方法的地址)。
在大多数情况下,这种开销不足以在性能分析中显示出来。

此外,在某些情况下,如果virtual可以在编译时确定要调用的函数,智能编译器将这样做,而不是在运行时确定。