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残念ながら、実際に使用しようとしない限り、どちらの場合もコンパイラにキャッチされません。戦略バリアントは、醜いものを回避し、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() を「特別な」実装として上書きすることを選択できます。戦略パターンは、通常の継承がもたらす機能を提供できなくなります。

戦略パターンの利点の 1 つは、BasedInterface が Impl 内で依存型を使用する必要がある場合、CRTP よりもはるかに簡単になることです。

template <class Impl>
class BaseInterface
{
    using SomeDerivedType = typename Impl::SomeType; 
}
于 2018-08-09T04:58:59.407 に答える