Хранение вектора std :: shared_ptr <Foo>, где Foo является шаблонным классом - PullRequest
3 голосов
/ 26 апреля 2011

У меня есть базовый класс, который я создал шаблон, потому что я хочу изменить тип, который требуется для нескольких функций, но я хочу получить из этих шаблонных базовых классов. Я хочу сохранить вектор этих классов. Моя идея состояла в том, чтобы создать не шаблонный базовый класс над всем в иерархии и использовать двойную диспетчеризацию для определения типа. Я делаю это "правильный путь"?

Вот фрагмент кода сценария:

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, но это кажется грязным. Так ли это твердое решение ситуации? Пожалуйста, посоветуйте (надеюсь, я не оставил явных синтаксических ошибок в примере)

(EDIT удален, глупая ошибка с моей стороны)

1 Ответ

3 голосов
/ 26 апреля 2011

Я думаю, вы почти поняли.Я написал бы класс посетителя как:

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 );
    };
};
...