1

我经常使用CRTP从基类调用派生类函数。它的好处是不会产生虚函数调用的成本,例如:

template< class Derived >
class Base
{
public:
   void foo() 
   {
      static_cast<Derived*>(this)->foo_impl(); // Non virtual derived class call
   }
};

class Derived : public Base<Derived> 
{
private:
   void foo_impl() 
   {
      // Do Stuff
   } 
};

C++11 引入了final将虚函数(或类)标记为 final 的语言标识符,告诉编译器不会再对该函数进行覆盖。

我的理解(来自 Going Native 2013 演示文稿)如果将虚函数标记为final编译器可以优化代码以消除虚函数调用的开销。

Ergo 在上面的示例中,可以删除 CRTP,并且仍然避免了虚函数调用的开销,前提是派生类将虚函数标记为finalie:

class Base
{
public:
   virtual void foo_impl() = 0;

   void foo() 
   {
      foo_impl(); // Non virtual derived class call
   }
};

class Derived : public Base 
{
public:
   // function marked as final, no virtual function call overhead
   virtual void foo_impl() final   
   {
      // Do Stuff
   } 
};

如果是这种情况,是否有关于哪种方法最好的建议?

是否仍应首选 CRTP,因为它保证函数调用是非虚拟的,而final不能依赖基于的优化?

4

2 回答 2

3

这取决于您如何传递实例。在一个翻译单元中考虑:

Derived d;
foo( &d );

在另一个:

void foo( Base* b )
{
    b->foo();
}

除了 LTO,编译器没有机会消除虚拟调用开销。

如果 OTOH,您有:

void foo( Derived* d )
{
    d->foo();
}

编译器现在可以足够聪明地优化 vtable 查找,因为它具有所有必要的信息。不过,我不认为这是有保证的。如果没有 final,vtable 查找仍然是必要的,因为它d可能指向派生出的东西,Derived它还有另一个实现foo_impl().

于 2013-10-14T15:48:14.723 回答
0

我的5美分:

当类名已知时,最近的 GCC 优化了虚函数。

标准还说,如果类名已知,则可以内联虚函数 - 例如,没有虚拟分派。

于 2015-09-28T21:47:17.300 回答