Qt中如何根据类名来实例化对象
对于Qt 来说,是可以做到运行时,根据对象的类名字(字符串)来获得对象的实例的,这点和一些语言的反射机制是一样的。
但是在Qt中,我们需要所额外的一步,就是注册。
只要做到了注册,我们就可以 自由的创建对象了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#include <QtCore> class Parser { public : virtual void parse() = 0; virtual ~Parser() {} }; class Parser1 : public Parser { public : Parser1() { qDebug() << "Parser1::Parser1()" ; } void parse() { qDebug() << "Parser1::parse()" ; } ~Parser1() { qDebug() << "Parser1::~Parser1()" ; } }; Q_DECLARE_METATYPE(Parser1) class Parser2 : public Parser { public : Parser2() { qDebug() << "Parser2::Parser2()" ; } void parse() { qDebug() << "Parser2::parse()" ; } ~Parser2() { qDebug() << "Parser2::~Parser2()" ; } }; Q_DECLARE_METATYPE(Parser2) void factory( const char * parserName ) { int id = QMetaType::type( parserName ); if (id == -1) return ; // ERROR HERE Parser *parser = static_cast <Parser*>(QMetaType::construct(id)); parser->parse(); delete parser; } int main () { qRegisterMetaType<Parser1>( "Parser1" ); qRegisterMetaType<Parser2>( "Parser2" ); qDebug() << "###### Trying create Parser1" ; factory( "Parser1" ); qDebug() << "###### Trying create Parser2" ; factory( "Parser2" ); } |
注册分为两步,定义的时候 使用 Q_DECLARE_METATYPE 宏。
使用的时候使用 qRegisterMetaType 函数
这样就可以在Qt 中动态地创建自己定义的类了。
但是这个方法,在注册 已有的 QWidget 和 QObject 的子类的时候会遇到问题。
原因是,在创建对象的时候,Qt 中有一个函数 qMetaTypeConstructHelper 会被调用,这个函数调用了欲创建类的复制构造函数,而复制构造函数 在 QWidget 和 QObject 的子类里是被禁用的。
解决的办法 就有两个,
一,启用 复制构造函数,
二,特化重写 qMetaTypeConstructHelper 函数。
复制构造函数 的启用 需要重新派生一个子类,就不多说了。
对于第二个方法,我们只要对于每一个特定的类 单独写一个函数就好了。如果使用宏,就会大大便捷这个过程。
代码如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
#include <QtCore> #define Q_DECLARE_QTBUILTIN_METATYPE(TYPE) \ template <> \ void *qMetaTypeConstructHelper( const TYPE *t) { \ Q_UNUSED(t) \ return new TYPE(); \ } \ Q_DECLARE_METATYPE(TYPE) Q_DECLARE_QTBUILTIN_METATYPE(QSettings) Q_DECLARE_QTBUILTIN_METATYPE(QTimer) void outputObject( const char * parseName) { QObject* obj = static_cast <QObject*>(QMetaType::construct(QMetaType::type(parseName))); qDebug() << obj; delete obj; } int main( int argc, char *argv[]) { qRegisterMetaType<QTimer>( "QTimer" ); qRegisterMetaType<QSettings>( "QSettings" ); outputObject( "QTimer" ); outputObject( "QSettings" ); QTimer* tmr = static_cast <QTimer*>(QMetaType::construct(QMetaType::type( "QTimer" ))); tmr->setInterval(50000); qDebug() << tmr->interval(); delete tmr; return 0; } |
转自:http://bbs.csdn.net/topics/390480286/
使用反射时同时要参考:http://www.cnblogs.com/liushui-sky/p/6422643.html
http://www.cnblogs.com/liushui-sky/p/5731477.html
Qt中如何根据类名来实例化对象的更多相关文章
- Spring中利用applicationContext.xml文件实例化对象和调用方法
Spring中实例化对象和调用方法入门 1.jar包和xml的准备 已上传至百度云盘,链接: https://pan.baidu.com/s/1CY0xQq3GLK06iX7tVLnp3Q 提取码: ...
- QT 中 关键字讲解(emit,signal,slot)
Qt中的类库有接近一半是从基类QObject上继承下来,信号与反应槽(signals/slot)机制就是用来在QObject类或其子类间通讯的方法.作为一种通用的处理机制,信号与反应槽非常灵活,可以携 ...
- QT中的线程与事件循环理解(1)
1.需要使用多线程管理的例子 一个进程可以有一个或更多线程同时运行.线程可以看做是“轻量级进程”,进程完全由操作系统管理,线程即可以由操作系统管理,也可以由应用程序管理.Qt 使用QThread 来管 ...
- python中如何统计一个类的实例化对象
类中的静态变量 需要通过类名.静态变量名 来修改 :通过对象不能修改 python中如何统计一个类的实例化对象?? class Person: #静态变量count,用于记录类被实例化的次数 coun ...
- [转]ThinkPHP中实例化对象M()和D()的区别,select和find的区别
1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法实例化模型无需用户为每个数据表定义模型类,如果D方法没有找到定义的模型类,则会 ...
- 1、c#中可以有静态构造方法,而java中没有,例如在单例模式中c#可以直接在静态构造中实例化对象,而java不可以
1.c#中可以有静态构造方法,而java中没有,例如在单例模式中c#可以直接在静态构造中实例化对象,而java不可以
- ThinkPHP中实例化对象M()和D()的区别,select和find的区别
原文:ThinkPHP中实例化对象M()和D()的区别,select和find的区别 1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在 ...
- spring中获取dao或对象中方法的实例化对象
spring中获取dao的中方法的实例化对象: //获取应用上下文对象 ApplicationContext ctx = new ClassPathXmlApplicationContext(&quo ...
- javascript中使用new与不使用实例化对象的区别
我们先来看个实例 function Me(name,age,job){ this.name = name; this.age = age; this.job = job; } 请问这以下两种实例化对象 ...
随机推荐
- shell 知识点
Q:1 Shell脚本是什么.它是必需的吗? 答:一个Shell脚本是一个文本文件,包含一个或多个命令.作为系统管理员,我们经常需要使用多个命令来完成一项任务,我们可以添加这些所有命令在一个文 ...
- mysql SQLyog导入csv数据失败怎么办?
分享下mysql使用SQLyog导入csv数据失败的解决方法 给mysql导入数据,选中某个表选择导入--导入使用本地csv数据即可,单有的时候不知道什么问题导入不成功!!! 给mysql导入数据,使 ...
- git 生成ssh keys
最近从svn转到gitlab 记录一下如何生成ssh keys 首先下载GitExtensions246SetupComplete.msi并安装,如果已经安装了git,那么安装途中就跳过就行 安装完毕 ...
- 通过show variables like ‘general_log%’可以看查询日志
mysql> show variables like 'general_log%'; +------------------+-----------------------------+ | V ...
- 每日英语:How Pop Culture Influences Chinese Travelers
Where are Chinese tourists going to next? Pop culture may hold some clues, from blockbuster rom-com ...
- js如何获取前后连续n天的时间
function GetDateStr(AddDayCount) { var dd = new Date(); dd.setDate(dd.getDate()+AddDayCount);//获取Add ...
- c++ primer读书笔记之c++11(四)
1 带有作用域的枚举 scoped-enumeration 相信大家都用过枚举量,都是不带有作用域的,在头文件中定义需要特别注意不要出现重名的情况.为了解决这种问题,c++11提供了带作用于的枚举. ...
- Lintcode:Longest Common Subsequence 解题报告
Longest Common Subsequence 原题链接:http://lintcode.com/zh-cn/problem/longest-common-subsequence/ Given ...
- 【Python】解决UnicodeEncodeError: 'ascii' codec can't encode character u'\u2019' in position 0: ordinal not in range(128)
指定文件字符集为utf-8 在文件头部加入以下代码: import sys reload(sys) sys.setdefaultencoding('utf-8')
- Ubuntu 16.04 64位安装arm-linux-gcc交叉编译器以及samba服务器
交叉编译器是嵌入式开发的必要工具,但是由于目前大多数人使用64位ubuntu,在照着很多教程做的时候,就会失败,失败原因是64位ubuntu需要额外安装32位的兼容包.以arm-linux-gcc-3 ...