10

我希望有一个在编译时选择的具有多种可能实现的接口。我看到 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不幸的是,在这两种情况下,编译器都不会捕获它,除非我真的尝试使用它。Strategy 变体对我来说似乎更好,因为它避免了丑陋static_cast,并且使用组合而不是继承。还有什么 CRTP 允许的,策略不允许的吗?为什么主要使用 CRTP 代替?

4

2 回答 2

1

策略模式的通常实现与您的 CRTP 实现完全一样。基类定义了某种算法,去掉了派生类中实现的一些部分。

所以 CRTP 实现了策略模式。您的 StrategyInterface 只是委托细节的实现,而不是策略模式的实现。

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

于 2014-01-11T14:04:31.153 回答
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; 
}
于 2018-08-09T04:58:59.407 回答