CRTP versus direct implementation of the function in the "derived"
I am trying to get a better understanding of CRTP. So far my understanding is that it allows one to write a functions like the following.
template <class T>
void foo(Base<T> x ) { x.do_stuff() }
Now, depending on the actual compile time derived object x
that is passed to the function foo()
, it will do different things.
However, I could have derived the class Derived
from Base
and masked/shadowed its do_stuff()
with a non-virtual but overridden Derived::do_stuff
.开发者_StackOverflow社区 So when exactly is it correct to use CRTP, rather the simplest non-trivial example which shows the advantage of CRTP over shadowing/masking.
The point of the CRTP is to be able to get the derived object's type without virtuality. If you do
struct B { void foo() const; }
struct D : B { void foo() const; }
void bar(const B& x) { x.foo(); }
then bar
calls B::foo
and not D::foo
when you pass a D
object, since foo
isn't a virtual function. If you want D::foo
to be called, then you need either virtual functions, or CRTP.
With the simplest kind of CRTP:
template <typename>
struct B { void foo() const; }
struct D : B<D> { void foo() const; }
template <typename T>
void bar(const B<T>& x)
{
static_cast<const T&>(x).foo();
}
this calls D::foo()
when you pass to bar
a D
object.
An alternative CRTP trick, which however forces D
to provide an implementation for foo
, is
template <typename T>
struct B
{
void foo() const { static_cast<const T*>(this)->foo_impl(); }
// default implementation if needed
// void foo_impl() const { ... }
};
struct D : B<D> { void foo_impl() const { ... } };
template <typename T>
void bar(const B<T>& x) { x.foo(); }
but you still need a template parameter for B
(so that foo
dispatches correctly), and therefore a template bar
function.
Also, if you don't do CRTP, you'd better have a virtual destructor, which might add unwanted overhead for lightweight classes which are meant to be completely inlined. With CRTP you will simply write a protected destructor (private destructor + friend T
in C++0x).
精彩评论