3

いくつかの関数に必要なタイプを変更したいので、テンプレートを作成した基本クラスがありますが、これらのテンプレート化された基本クラスから派生したいと思います。これらのクラスのベクトルを保存したいと思います。私のアイデアは、階層内のすべての上にテンプレート化されていない基本クラスを作成し、ダブルディスパッチを使用してタイプを把握することでした。私はこれを「正しい方法」で行っていますか?

シナリオのコードスニペットは次のとおりです。

class FooBase
{
public:
    virtual void Accept( Visitor &v );
};

template<class T>
class Foo : public FooBase
{
public:
    virtual void DoThing( const T & );
    virtual void Accept( Visitor &v) = 0;

};

template<>
class Foo<Bar> : public FooBase
{
public:
    virtual void Accept( Visitor &v )
    {
        v.HandleBar( *this );
    }
};

template<>
class Foo<Baz> : public FooBase
{
public:
    virtual void Accept( Visitor &v )
    {
        v.HandleBaz( *this );
    }
};

//およびFoo、Fooから派生した多くのクラス

その後、別のクラスで

class Visitor
{
public:
    virtual void HandleBar( Foo<Bar> &f ) = 0;
    virtual void HandleBaz( Foo<Baz> &f ) = 0;
};

class Manager : public Visitor
{
public:
    void AddFoo( FooBase& f )
    {
        a.push_back( f );
    }

    void RunAll()
    {
        for ( std::vector<std::shared_ptr<FooBase> >::iterator it = a.begin(); it != a.end(); ++it )
        {
            (*it)->Accept( *this );
            // do common action that doesn't depend on types
        }
    }

    virtual void HandleBar( Foo<Bar> &f )
    {
         Bar item = GetBarItemFunction(); // not shown
         f.DoThing( item );
    }
    virtual void HandleBaz( Foo<Baz> &f )
    {
         Baz item = GetBazItemFunction(); // not shown
         f.DoThing( item );
    }

private:
    std::vector<std::shared_ptr<FooBase> > a;
};

これが「最善の」方法かどうかはわかりません。dynamic_castingを使用できますが、それは汚い感じがします。それで、これは状況に対する固溶体ですか?アドバイスしてください(例に明白な構文エラーを残さなかったと思います)

(編集は削除されました、私の側の愚かなエラーでした)

4

1 に答える 1

3

私はあなたがほとんどそれを持っていると思います。私はビジタークラスを次のように書きます:

class Visitor
{
public:
    virtual void HandleFoo( Foo<Bar> &f ) = 0;
    virtual void HandleFoo( Foo<Baz> &f ) = 0;
    //default implementation for unknown Foo types:
    virtual void HandleFoo( FooBase &f ) = 0; 
};

これで、テンプレート化されたFooクラスを特殊化する必要はなく、アプリケーションが必要とする可能性のあるすべてのクラスTで機能するように、次のように記述できます。正しいオーバーロードされたHandleFoo関数は、Fooで使用されるテンプレートタイプに基づいて選択されます。デフォルトの動作が呼び出されないようにするには、ビジタークラスにメソッドを追加する必要があります。

template<class T>
class Foo : public FooBase
{
public:
    virtual void DoThing( const T & );
    virtual void Accept( Visitor &v) {
        v.HandleFoo( *this );
    };
};
于 2011-04-26T04:14:26.480 に答える