我正在使用类工厂动态创建对象。我用过这个answer因为它的简单性(并且因为我使用的是 Qt)。
但现在我意识到我必须向构造函数添加一个参数
Item(bool newItem /* = true*/);
而不是
Item();
引用答案中的代码:
template <typename T>
class ClassFactory
{
public:
template <typename TDerived>
void registerType(QString shape)
{
_createFuncs[shape] = &createFunc<TDerived>;
}
T* create(QString shape)
{
typename QMap<QString, PCreateFunc>::const_iterator it = _createFuncs.find(shape);
if (it != _createFuncs.end())
{
return it.value()();
}
return NULL;
}
private:
template <typename TDerived>
static T* createFunc()
{
return new TDerived();
}
typedef T* (*PCreateFunc)();
QMap<QString, PCreateFunc> _createFuncs;
};
我注册了该类(class)
classFactory.registerType <Type1_Item> ("type1");
需要时我打电话
Item* item = classFactory.create("type1");
我试图在类工厂中添加一个附加参数,以表示构造函数参数,但我的尝试都导致错误。
为什么我需要它:简单的例子:
创建一个新对象 - 设置默认值;对于某些对象,它需要一个打开的文件对话框,因为必须从文件加载数据。
加载对象 - 填充数据,包括包含文件信息的对象的文件名
为了能够调用“加载”函数,一个对象必须存在 - 这意味着如果我创建一个新对象,即使我不需要它,我也会触发一个打开文件对话框。
我看到的解决方法是先有一个构造函数,后跟一个设置函数。但是...这意味着构造一个对象总是需要两个函数调用,这似乎是糟糕的设计。
这就是为什么我正在寻找一种使用简单调用来注册和调用类的方法,例如
classFactory.registerType <Type1_Item> ("type1", bool);
Item* item = classFactory.create("type1", true);
这可能吗?我该怎么做?
最佳答案
我能想到的一种方法是要求参数完全匹配。首先,我们将使用 boost::any
存储我们的函数。 。这是因为它们可能有不同的类型,所以我们需要一个异构容器:
QMap<QString, boost::any> _createFuncs;
我们的register
函数将创建一个特定的函数指针来存储在所述any
中:
template <typename TDerived, typename... T>
void registerType(QString shape)
{
_createFuncs[shape] = &createFunc<TDerived, T...>;
}
其中 createFunc
现在需要额外的参数:
template <typename TDerived, typename... Args>
static T* createFunc(Args... args)
{
return new TDerived(args...);
}
关键是我们在创作方面做了什么。我们需要检查我们为特定类型存储的 any
是否是正确的类型:
template <typename... Args>
T* create(QString shape, Args... args)
{
using FPtr = T*(*)(Args...);
auto it = _createFuncs.find(shape);
if (it != _createFuncs.end())
{
// ok, it points to some any. is it the right any?
FPtr* fptr = boost::any_cast<FPtr>(&it.value());
if (fptr) {
return (*fptr)(args...);
}
// alternatively to the above, we can have createFunc
// throw bad_any_cast if you pass the wrong arguments
// which could be a loud, explicit failure rather than
// a silent one
return boost::any_cast<FPtr>(it.value())(args...);
}
return nullptr;
}
这将允许它工作:
classFactory.registerType<Item, bool>("type1");
^^^^^^
arg list
Item* item = classFactory.create("type1", true);
Item* item2 = classFactory.create<bool>("type1", 1);
但这会失败,因为 any
采用 bool
,而不是 int
:
Item* item3 = classFactory.create("type1", 1);
关于c++ - 我可以为带参数的构造函数创建类工厂吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30174635/