23

在 C++ 中,我的理解是可以内联虚函数,但通常会忽略内联的提示。似乎内联虚函数没有太大意义。

是对的吗?

任何人都可以给出一个内联虚函数好的例子吗?

4

3 回答 3

43

为了完全回答这个问题,我们需要了解存在的属性virtual独立地应用于函数本身以及对该函数的调用。有虚函数和非虚函数。这些函数有虚拟和非虚拟调用。

存在的属性也是如此inline。有内联函数和非内联函数。并且有对这些函数的内非内联调用。

这些属性 -virtualinline- 当应用于函数本身时,不会冲突。他们根本没有理由也没有机会发生冲突。说明符对函数本身的唯一inline更改是它修改了该函数的一个定义规则:该函数可以在多个翻译单元中定义(并且必须在使用它的每个翻译单元中定义)。唯一virtual改变说明符的是包含该函数的类变成多态的。它对函数本身没有实际影响。

virtual所以,同时声明一个函数绝对没有问题inline。任何冲突都没有任何根据。这在 C++ 语言中是完全合法的。

struct S {
  virtual void foo(); 
};

inline void S::foo() // virtual inline function - OK, whatever
{
}

然而,当人们问这个问题时,他们通常对函数本身的属性不感兴趣,而是对函数调用的特征感兴趣。

虚拟调用的定义特征是它在运行时被解析,这意味着通常不可能内联真正的虚拟调用:

S *s = new SomeType;
s->foo(); // virtual call, in general case cannot be inlined

但是,如果调用本身是非虚拟的(即使它转到虚拟函数),则内联根本不是问题:

S *s = new SomeType;
s->S::foo(); // non-virtual call to a virtual function, can easily be inlined

当然,在某些情况下,优化编译器可能能够在编译时找出虚拟调用的目标,甚至内联这样的虚拟调用。在某些情况下,这很容易:

S ss;
ss.foo(); // formally a virtual call, but in practice it can easily be inlined

在某些情况下,它更复杂,但仍然可行:

S *s = new S;
s->foo(); // virtual call, but a clever compiler might be able
          // to figure out that it can be inlined
于 2010-01-25T06:05:05.340 回答
14

在正常情况下,将通过指向函数的指针(包含在类的 vtable 中)调用虚函数。在这种情况下,只有当编译器可以静态确定调用函数的实际类型时,才能内联生成虚函数调用,而不仅仅是它必须是类 X 或从 X 派生的东西。

内联虚函数第一次有意义的时候是如果您遇到性能关键情况,并且知道类将经常以允许编译器静态确定实际类型的方式使用(并且至少一个目标编译器优化了通过指针调用)。

于 2010-01-25T04:47:24.803 回答
4

您可以将虚函数作为内联函数。使函数调用内联的决定不仅仅是在编译时做出的。它可以在编译到 rutime 之间的任何时间。您可以参考 Herb Sutter 的这篇文章。内联 Redux

于 2010-01-25T05:22:07.880 回答