克隆抽象基类(不干涉派生)

时间:2010-08-17 19:09:47

标签: c++ copy abstract-class clone

我遇到了一个具有挑战性的问题,这个问题一直无法解决 - 希望到现在为止。我正在开发自己的框架,因此试图为用户提供所有代码复杂性的灵活性。

首先,我有一个用户可以实现的抽象基类,显然简化了:

class IStateTransit
{
public:
    bool ConnectionPossible(void) = 0;
}

// A user defines their own class like so
class MyStateTransit : public IStateTransit
{
public:
    bool ConnectionPossible(void){ return true; }
}

接下来,我定义一个工厂类。用户可以注册自己的自定义状态传输对象,稍后只需使用他们选择的字符串标识符即可引用它们:

class TransitFactory : public Singleton<TransitFactory>
{
public:
    template<typename T> void RegisterStateTransit(const string& name)
    {
        // If the transit type is not already registered, add it.
        if(transits.find(name) == transits.end())
        {
            transits.insert(pair<string, IStateTransit*>(name, new T()));
        };
    }

    IStateTransit* TransitFactory::GetStateTransit(const string& type) const
    {
        return transits.find(type)->second;
    };

private:
    map<string, IStateTransit*> transits;
}

现在问题是(可能很明显)每当用户通过调用GetStateTransit请求传输时,系统当前一直保持返回相同的对象 - 指向同一对象的指针。我想改变它。

问题:如何在不需要用户定义自己的复制构造函数或virtual constructor的情况下返回原始IStateTransit对象的新(克隆)。理想情况下,我会以某种方式喜欢GetStateTransit方法,以便能够将IStateTransit对象转换为它在运行时的派生类型,并返回该实例的克隆。最大的障碍是我不希望用户必须实现任何额外的(可能是复杂的)方法。

4小时的谷歌搜索和尝试让我无处可去。得到答案的人是英雄!

3 个答案:

答案 0 :(得分:5)

问题是你没有类型信息来执行克隆,因为你只有一个指向基类类型的指针,并且不知道哪些派生类型已经实现并且可用。

我认为有一个原因是4小时的谷歌搜索没有任何进展。如果希望IStateTransit可以克隆,则必须有一个接口,派生类实现者提供某种克隆方法实现。

如果这不是你想听到的,我很抱歉。

但是,实现克隆方法不应该是一个很大的负担。只有类实现者知道如何复制类,给定正确的复制构造函数,可以为叶节点类实现克隆,如下所示:

Base* clone() const
{
    return new MyType(*this);
}

你甚至可以对它进行宏观调整;虽然我不愿意。

答案 1 :(得分:1)

如果我正确理解了问题,则不应将new T -s插入到地图中,而应将其创建为创建新T-s的对象。

struct ICreateTransit
{
    virtual ~ICreateTransit() {}
    virtual IStateTransite* create() const = 0;

};

template <class T>
struct CreateTransit: public ICreateTransit
{
    virtual IStateTransit* create() const { return new T(); }
};

现在插入:

transits.insert(pair<string, ICreateTransit*>(name, new CreateTransit<T>()));

并使用以下内容检索“副本”

return transits.find(type)->second->create(); //hopefully with error handling

不应该修改StateTransit<T>,因此如果默认值没有,T会保留{{1}}的副本。

我认为像这样的技术的通用名称叫做“类型擦除”(派生类型“记住”特定类型,尽管基类不知道那些)。

答案 2 :(得分:0)

这个问题对我来说听起来abstract factory模式可能有所帮助。使用此模式,库客户端可以定义框架如何构建其类型。客户端可以将自己的工厂子类注入到框架中,并定义应该构建哪些类型。

你需要的是(另外) 工厂的基础类 作为客户:派遣一家混凝土工厂 一种将(作为客户端)工厂的子类型注入框架的方法 调用工厂方法来创建新类型。

这对你有帮助吗?