我想要一个可以有多种可能实现的接口,并且可以在编译时进行选择。我看到CRTP是实现这一目标的首选习惯用语。为什么会是这样?另一种替代方案是策略模式,但是我在任何地方都没有看到提及这种技术:
template <class Impl>
class StrategyInterface
{
public:
void Interface() { impl.Implementation(); }
void BrokenInterface() { impl.BrokenImplementation(); }
private:
Impl impl;
};
class StrategyImplementation
{
public:
void Implementation() {}
};
template <class Impl>
class CrtpInterface
{
public:
void Interface() { static_cast<Impl*>(this)->Implementation(); }
void BrokenInterface() { static_cast<Impl*>(this)->BrokenImplementation(); }
};
class CrtpImplementation : public CrtpInterface<CrtpImplementation>
{
public:
void Implementation() {}
};
StrategyInterface<StrategyImplementation> str;
CrtpImplementation crtp;
BrokenInterface
在这两种情况下都不会被编译器捕获,除非我实际尝试使用它。对我来说,策略模式似乎更好,因为它避免了丑陋的 static_cast
,并且它使用组合而不是继承。除了CRTP之外,还有其他任何CRTP允许但策略模式不允许的吗?为什么CRTP被主要使用?
((Impl*)this)->Implementation()
,因为它允许您将CRTP类用作私有基类。 - Simplereinterpret_cast
不会应用基类到派生类的指针偏移量。C++11 有特殊措辞,使得 C 式转换执行static_cast
,但忽略可访问性。你有一个使用static_cast
的例子吗? - Simplestatic_cast<Impl*>(this)
替换为self()
,并编写Impl* self() { return static_cast<Impl*>(this); }
和Impl const* self() const { return static_cast<Impl*>(this); }
。还要在self()
方法中添加一些static_assert
来断言Impl
是子类。 - Yakk - Adam Nevraumont