我遇到了一个具有挑战性的问题,这个问题一直无法解决 - 希望到现在为止。我正在开发自己的框架,因此试图为用户提供所有代码复杂性的灵活性。
首先,我有一个用户可以实现的抽象基类,显然简化了:
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小时的谷歌搜索和尝试让我无处可去。得到答案的人是英雄!
答案 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模式可能有所帮助。使用此模式,库客户端可以定义框架如何构建其类型。客户端可以将自己的工厂子类注入到框架中,并定义应该构建哪些类型。
你需要的是(另外) 工厂的基础类 作为客户:派遣一家混凝土工厂 一种将(作为客户端)工厂的子类型注入框架的方法 调用工厂方法来创建新类型。
这对你有帮助吗?