CRTP与“派生”中函数的直接实现

时间:2011-08-30 07:10:11

标签: c++ templates crtp

我正在努力更好地了解CRTP。到目前为止,我的理解是它允许人们编写如下函数。

template <class T>
void foo(Base<T> x ) { x.do_stuff() }

现在,根据传递给函数x的实际编译时派生对象foo(),它将执行不同的操作。

但是,我可以从Derived派生出类Base,并使用非虚拟但被覆盖的do_stuff()屏蔽/隐藏其Derived::do_stuff。因此,当使用CRTP正确时,最简单的非平凡示例显示了CRTP优于阴影/屏蔽的优势。

1 个答案:

答案 0 :(得分:6)

CRTP的目的是能够在没有虚拟性的情况下获取派生对象的类型。如果你这样做

struct B { void foo() const; }
struct D : B { void foo() const; }

void bar(const B& x) { x.foo(); }

然后bar在您传递B::foo对象时调用D::foo而不调用D,因为foo不是虚函数。如果您希望调用D::foo,则需要虚拟函数或CRTP。

使用最简单的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();
}

当您传递给D::foo() bar个对象时,会调用D

另一种CRTP技巧是强制Dfoo提供实施,

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(); }

但您仍需要B的模板参数(以便foo正确调度),因此需要模板bar功能。

另外,如果你不做CRTP,你最好有一个虚拟析构函数,这可能会为轻量级类增加不必要的开销,这些类本意味着完全内联。使用CRTP,您只需编写一个受保护的析构函数(C ++ 0x中的私有析构函数+ friend T)。