存储std::shared_ptr<Foo>向量,其中Foo是一个模板类

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_cast,但那感觉很糟糕。所以这是否是解决问题的可靠方案?请给予建议(希望我在示例中没有留下任何明显的语法错误)

(编辑已删除,是我自己的愚蠢错误)

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。根据Foo中使用的模板类型选择正确的重载HandleFoo函数。您仍然需要向访问者类添加方法以避免调用默认行为。
template<class T>
class Foo : public FooBase
{
public:
    virtual void DoThing( const T & );
    virtual void Accept( Visitor &v) {
        v.HandleFoo( *this );
    };
};

哇,我一直在苦苦挣扎专业化问题(试图重用通用代码等)。你的建议正是我所需要的!谢谢! - Matt
另一个问题可能是你真的需要访问者模式吗?你能否只将函数本身进行模板化?(而不是整个类) - hifier
但是,我怎么知道什么时候调用GetBarItemFunction()或者GetBazItemFunction()呢?这是代码中不同的Foo模板特化分歧的地方... - Matt
我不确定那个方法对你的情况是否适用。这取决于模板类型在概念上是否对Foo的类型有所贡献,或者它是否仅适用于某些操作。显然,我简化了这个问题,所以你需要做出决定。一个有帮助的方法是思考Foo正在维护的状态——这种状态是否依赖于模板类型?如果是,那么我认为这个方法可能有效;如果不是,那么我认为可能有其他方法可以解决问题。 - hifier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接