43

Curiously Recurring Template Patternを使用した静的ポリモーフィズムのメカニズムを理解しています。私はそれが何のために良いのか理解していません。

宣言された動機は次のとおりです。

速度のために、動的ポリモーフィズムの柔軟性をいくらか犠牲にしています。

しかし、次のような非常に複雑なことを気にする必要はありません。

template <class Derived>
class Base
{
public:
    void interface()
    {
         // ...
         static_cast<Derived*>(this)->implementation();
         // ...
    }
};

class Derived : Base<Derived>
{
private:
     void implementation();
};

あなたができるとき:

class Base
{
public: 
    void interface();
}

class Derived : public Base
{
public: 
    void interface();
}

私の推測では、コードにセマンティックの違いはなく、単に C++ スタイルが優れているだけであるということです。

ハーブ・サッターはその中で次のように書いてExceptional C++ style: Chapter 18います。

仮想機能を非公開にすることを好みます。

もちろん、なぜこれが良いスタイルなのか、徹底解説付き。

このガイドラインの文脈では、最初の例は良いです。

このvoid implementation()例の関数は、クラスのカスタマイズを実行するためにここにあるため、仮想のふりをすることができます。したがって、それは非公開にする必要があります。

そして、2 番目の例は悪いです。

カスタマイズを実行するためにパブリック インターフェイスをいじるべきではありません。

私の質問は:

  1. 静的ポリモーフィズムについて何が欠けていますか? すべては優れた C++ スタイルに関するものですか?
  2. いつ使用する必要がありますか?いくつかのガイドラインは何ですか?
4

3 に答える 3

4

あなたが提供するリンクは、静的ポリモーフィズムの例としてブーストイテレータに言及しています。STL イテレータもこのパターンを示します。例を見て、これらのタイプの作成者がこのパターンが適切であると判断した理由を考えてみましょう。

#include <vector>
#include <iostream>
using namespace std;
void print_ints( vector<int> const& some_ints )
{
    for( vector<int>::const_iterator i = some_ints.begin(), end = some_ints.end(); i != end; ++i )
    {
        cout << *i;
    }
}

では、どのように実装しint vector<int>::const_iterator::operator*() const;ますか?これに多形性を使用できますか? うーん、ダメ。仮想関数のシグネチャは何でしょうか? void const* operator*() const? だめだ!型が消去されました (int から void* に劣化)。代わりに、奇妙に繰り返されるテンプレート パターンが、反復子の型を生成するのに役立ちます。上記を実装する必要がある反復子クラスの大まかな概算は次のとおりです。

template<typename T>
class const_iterator_base
{
public:
    const_iterator_base():{}

    T::contained_type const& operator*() const { return Ptr(); }
    T::contained_type const& operator->() const { return Ptr(); }
    // increment, decrement, etc, can be implemented and forwarded to T
    // ....
private:
    T::contained_type const* Ptr() const { return static_cast<T>(this)->Ptr(); }
};

従来の動的ポリモーフィズムでは、上記の実装を提供できませんでした!

関連する重要な用語は、パラメトリック ポリモーフィズムです。これにより、C++ で奇妙に繰り返されるテンプレート パターンを使用して、たとえば python で同様の API を実装できます。これが役に立てば幸いです!

このすべての複雑さの原因と、Java や C# などの言語がほとんどそれを回避しようとする理由、つまり型消去を突き止めることは価値があると思います。C++ ではObject、有用な情報を持つ有用なすべてを含む型はありません。代わりに、私たちは持っvoid*ていvoid*ます。崩壊したインターフェイスがある場合、void*回復する唯一の方法は、危険な仮定を作成するか、余分な型情報を保持することです。

于 2013-09-28T03:46:04.487 に答える