我有很多类都是从同一个父类派生的,并且需要从一个简单的QString实例化那些类
我想象过使用带有QString键的QMap并将类的“引用”作为值可以解决问题
class Feat : public QObject { ... } // Base class
QMap<QString, ...> feats;
但是我不知道如何从这里走,得到我想要的语法是什么。
答案 0 :(得分:1)
鉴于您的类继承自QObject
,因此您可以使用QMetaType
system从其名称构造实例作为字符串。元对象系统是Qt的关键部分,它提供了名称类型和 IDs 类型之间的映射。
您需要首先注册您的类型,以便元对象系统知道如何使用以下方法来处理它:
Q_DECLARE_METATYPE(Feat)
然后,每当要使用对象名称构造对象时,都可以使用:
int type_id = QMetaType::type("Feat");
void *obj = QMetaType::create(type_id);
现在obj
指向Feat
的动态分配实例。请注意,完成后需要释放对象(使用QMetaType::destroy(type_id, obj);
);将其包装在某种受保护的指针中(std::unique_ptr
,QPointer
等);或确保它有一个QObject
父级,它将自动释放它。
另外,请注意,您需要注册要以这种方式使用的每种类型。
答案 1 :(得分:0)
由于构造函数不是“常规”函数,因此您需要类似工厂模式的东西,即存储返回给定类型新实例的函数;一种简单的C ++ 11 +实现方法是将QString
映射到std::function
并返回新实例(作为指向基类的指针):
QMap<QString, std::function<Feat *()>> feats;
feats["Feat1"] = []() { return new Feat1; };
feats["Feat2"] = []() { return new Feat2; };
根据需要进行调整,如果您需要传递参数以进行构造,或者您希望返回一些智能指针(例如unique_ptr
)。另外,根据您的喜好,您可能会或可能不喜欢将此代码隐藏在宏后面。
#define REGISTER_FEAT(FeatClass) feats[#FeatClass] = []() { return new FeatClass;}
// to be used as
REGISTER_FEAT(Feat1);
REGISTER_FEAT(Feat2);
如果您确定不需要捕获这些lambda中的任何内容,也可以避免std::function
开销,但是除非您有真正的理由(构建时间或运行时开销),否则我不会担心这一点。 ?)以避免它。
偶然地,即使Digia将Qt容器确认为“生命支持模式”,所以,除非您有充分的理由使用它们(例如,稳定的二进制接口,不同编译器之间的性能更一致-尽管通常更糟),否则您会内置的“ STL”副本(例如std::map
或std::unordered_map
)通常可以更好地为其提供服务。