在 C++ 中,我的理解是可以内联虚函数,但通常会忽略内联的提示。似乎内联虚函数没有太大意义。
是对的吗?
任何人都可以给出一个内联虚函数好的例子吗?
在 C++ 中,我的理解是可以内联虚函数,但通常会忽略内联的提示。似乎内联虚函数没有太大意义。
是对的吗?
任何人都可以给出一个内联虚函数好的例子吗?
为了完全回答这个问题,我们需要了解存在的属性virtual
独立地应用于函数本身以及对该函数的调用。有虚函数和非虚函数。这些函数有虚拟和非虚拟调用。
存在的属性也是如此inline
。有内联函数和非内联函数。并且有对这些函数的内联和非内联调用。
这些属性 -virtual
和inline
- 当应用于函数本身时,不会冲突。他们根本没有理由也没有机会发生冲突。说明符对函数本身的唯一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
在正常情况下,将通过指向函数的指针(包含在类的 vtable 中)调用虚函数。在这种情况下,只有当编译器可以静态确定调用函数的实际类型时,才能内联生成虚函数调用,而不仅仅是它必须是类 X 或从 X 派生的东西。
内联虚函数第一次有意义的时候是如果您遇到性能关键情况,并且知道类将经常以允许编译器静态确定实际类型的方式使用(并且至少一个目标编译器优化了通过指针调用)。
您可以将虚函数作为内联函数。使函数调用内联的决定不仅仅是在编译时做出的。它可以在编译到 rutime 之间的任何时间。您可以参考 Herb Sutter 的这篇文章。内联 Redux