开发者

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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜