策略和CRTP的静态多态性有什么区别?

时间:2014-01-11 13:57:38

标签: c++ design-patterns inheritance crtp static-polymorphism

我希望在编译时选择具有多个可能实现的接口。我看到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?

2 个答案:

答案 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; 
}