我试图更好地了解 CRTP。到目前为止,我的理解是它允许编写如下函数。
template <class T>
void foo(Base<T> x ) { x.do_stuff() }
现在,根据传递给函数
x
的实际编译时派生对象 foo()
,它会做不同的事情。但是,我可以从
Derived
派生类 Base
并使用非虚拟但覆盖的 do_stuff()
屏蔽/隐藏其 Derived::do_stuff
。所以什么时候使用 CRTP 是正确的,而不是最简单的非平凡示例,它显示了 CRTP 优于阴影/屏蔽的优势。 最佳答案
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 技巧,但它强制
D
提供 foo
的实现,是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,您只需编写一个 protected 析构函数(C++0x 中的私有(private)析构函数 +
friend T
)。关于c++ - CRTP 与 "derived"中函数的直接实现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7239771/