我希望在编译时选择具有多个可能实现的接口。我看到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?
答案 0 :(得分:1)
策略模式的通常实现与您的CRTP实现完全相同。基类定义了某种算法,省略了在派生类中实现的一些部分。
因此CRTP实现了策略模式。您的StrategyInterface只是委派细节的实现,而不是策略模式的实现。
虽然两个实现都达到了相同的效果,但我更喜欢CRTP,因为它会利用可能的空基类优化。
答案 1 :(得分:0)
除了静态多态性之外,CRTP还提供了覆盖基类函数的功能,因为它使用了继承机制。
template <class Impl>
class BaseInterface
{
void genericFunc() { some implementation; }
}
如果使用CRTP,则派生类可以选择覆盖genericFunc()作为“特殊”实现,以防genericFunc()不合适。策略专利将无法提供正常继承带来的功能。
该策略模式的一个优势是,如果BasedInterface需要在Impl中使用依赖类型,那将比CRTP容易得多。
template <class Impl>
class BaseInterface
{
using SomeDerivedType = typename Impl::SomeType;
}