VTable上下文中的Virtual Method调用和Direct Method调用有什么区别? 如果Virtual&amp ;;如何解决方法参考直接电话?
答案 0 :(得分:2)
理论上,没有这样的东西存在,C ++标准没有定义它(虚拟调用是定义的,但没有指定它们必须如何工作,不存在VTable这样的东西)。
实际上,虚拟调用会在我知道的每个编译器上使用vtable。这是每个类的一个地址表的内存开销,其中包含虚拟成员(每个类,每个实例不!)和每个实例一个指向该表的指针。
虚拟调用 - 取决于体系结构 - 来自该表的加载,然后是对加载的地址的调用,或者所谓的间接调用(它是相同的,但在一条指令中)。
直接调用只是对编译器知道的地址的普通函数调用(单指令)(共享库调用存在一些异常,也可能使用间接调用甚至双间接调用)。每当编译器100%确定对象的运行时类型或通过范围解析(operator::
)明确告知它时,就是使用的。
直接和间接调用之间的最大区别传统上是分支预测和流水线操作,使得间接调用很多更加昂贵(10-15次),但是更新的CPU在任何一种情况下都能很好地实现这一点(现代CPU上有专用的间接调用缓存) 我不会说这种差异是不存在的或者是不可忽视的,但现在肯定没有什么大不了的。
答案 1 :(得分:1)
定义了虚方法的类将向该类添加隐藏指针成员。指针指向所谓的V表,这是一个与该类的虚方法相对应的函数指针块。
从具有虚方法的类派生的每个类都继承此隐藏指针成员。但是,此外,每个这样的类都有自己的V表。因此,派生类的实例化会将此指针初始化为它自己的V表。
这样,当使用虚方法在基类上调用虚方法时,当它查询V表指针时,该指针实际指向派生类的表,这就是从基类调用虚方法的方法。实际上调用派生类的实现。因此,遇到虚拟方法的编译器使用此代码解析调用,该代码通过V表指针进行查找。
直接方法调用没有V表查找代码。编译器只是解析对与该方法对应的函数的地址的调用。