我经常使用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
,编译器可以优化代码以消除虚拟函数调用的开销。
因此,在上面的示例中,可以删除 CRTP,并且仍然可以避免虚拟函数调用的开销,只要派生类将虚拟函数标记为 final
即:
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
的优化?
最佳答案
这取决于您如何传递实例。考虑在一个翻译单元中:
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()
的实现。
关于c++ - CRTP vs 过载和最终,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19363884/