在C ++中,我的理解是可以内联虚函数,但通常会忽略内联提示。似乎内联虚函数没有多大意义。
是吗?
任何人都可以提供一个内联虚函数好的案例吗?
答案 0 :(得分:39)
为了完全回答这个问题,我们需要了解virtual
的属性是独立地应用于函数本身以及对该函数的调用。有虚拟和非虚拟功能。有对这些功能的虚拟和非虚拟调用。
inline
的属性也是如此。有iniline和non-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
答案 1 :(得分:14)
在正常情况下,将通过指向函数的指针调用虚函数(该函数包含在类'vtable中)。在这种情况下,如果编译器可以静态地确定将调用该函数的实际类型,而不仅仅是它必须是X类或从X派生的东西,则只能内联生成虚函数调用。
内联虚函数有意义的主要时间是你是否有性能危急情况,并且知道一个类经常以允许编译器静态确定实际类型的方式使用(以及至少一个目标编译器)通过指针优化调用。)
答案 2 :(得分:4)
您可以将虚拟功能设置为内联。使函数调用内联的决定不仅仅是在编译时进行的。它可以是编译到rutime之间的任何时间。你可以参考Herb Sutter的这篇文章。 Inline Redux