首页 > 解决方案 > C++ 虚函数是否总是在运行时解析?

问题描述

我对 C++ 虚函数的解析时间有疑问。从 C++ Primer 的 OOP 一章中,它提到:

对虚拟函数的调用可能会在运行时得到解决 当通过引用或指针调用虚拟函数时,编译器会生成代码以在运行时决定调用哪个函数。被调用的函数是对应于绑定到该指针或引用的对象的动态类型的函数。

我理解上面的描述:当一个虚函数被执行时,哪个版本真正被解析取决于调用指针/引用的实际类型。如果指针/引用的实际类型是基类,则基类的虚函数是实际运行的,反之亦然。它显然需要在运行时完成。

但是,C++ 入门中上述语句后面的示例让我困惑了一段时间:

double print_total(ostream &os, const Quote &item, size_t n)
{
  // depending on the type of the object bound to the item parameter
  // calls either Quote::net_price or Bulk_quote::net_price
  double ret = item.net_price(n);
}

// Quote is base class, Bulk_quote is derived class
Quote base("0-201-82470-1", 50);
print_total(cout, base, 10); // calls Quote::net_price
Bulk_quote derived("0-201-82470-1", 50, 5, .19);
print_total(cout, derived, 10); // calls Bulk_quote::net_price

我的问题是:

  1. 据我了解,在此示例中,编译器能够在编译时知道实例基实例派生的“真实类型”,因为它们只是在草图中明确声明!所以,我认为这个例子的解决时间可以在编译时。我说得对吗?
  2. 虚函数的解析时间可以是编译时间吗?或者为了方便起见,C++ 只是让所有虚函数在运行时解析?由于 C++ 入门书说:对虚拟函数的调用可能在运行时得到解决,我不太确定运行时是否都是如此。

我认为真正理解虚函数的解析时间对每个 C++ 用户来说都非常重要。我试图找到有关编译时间/运行时间的知识,但没有一个可以帮助我弄清楚我的问题。有没有人对我的问题有任何想法。先感谢您!

标签: c++polymorphismvirtual-functions

解决方案


一般来说,编译器会创建一个vtable虚拟方法调用,并通过它调度虚拟方法调用,即在调用中增加了一层间接性。

但是优化编译器确实试图避免这种情况。这种优化通常称为“去虚拟化”。何时以及如何工作在很大程度上取决于相关的编译器和代码。 这是一篇关于它的不错的博客文章。

更多资源:

谈话:Matt Godbolt 谈 LLVM 中的投机去虚拟化

演讲:2016 LLVM 开发者会议:P. Padlewski “LLVM 中的去虚拟化”</a>

演讲:2018 LLVM 开发者会议:P. Padlewski “LLVM 中的声音去虚拟化”</a>

论文:Ishizaki 等人,2000 年,“Java™ 即时编译器的去虚拟化技术研究”

论文:Padlewski 等人,2020 年,“LLVM 中虚拟指针的不变性建模”


推荐阅读