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

What is the difference between Strategy and CRTP for static polymorphism?

本文关键字:什么 区别 CRTP 多态性 策略 静态      更新时间:2023-10-16

我想要一个接口,其中包含在编译时选择的多个可能的实现。我看到 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 实现完全相同。基类定义某种算法,释放在派生类中实现的一些部分。

因此,CRTP 实现了策略模式。您的策略接口只是委托细节的实现,而不是策略模式的实现。

虽然您的两个实现都实现了相同的效果,但我更喜欢 CRTP,因为它将利用可能的空基类优化。

除了静态多态性之外,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; 
}