对于Qt 来说,是可以做到运行时,根据对象的类名字(字符串)来获得对象的实例的,这点和一些语言的反射机制是一样的。

但是在Qt中,我们需要所额外的一步,就是注册。
只要做到了注册,我们就可以 自由的创建对象了。

C/C++ code

 

?

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 函数。

复制构造函数 的启用 需要重新派生一个子类,就不多说了。
对于第二个方法,我们只要对于每一个特定的类 单独写一个函数就好了。如果使用宏,就会大大便捷这个过程。
代码如下。

C/C++ code

 

?

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中如何根据类名来实例化对象的更多相关文章

  1. Spring中利用applicationContext.xml文件实例化对象和调用方法

    Spring中实例化对象和调用方法入门 1.jar包和xml的准备 已上传至百度云盘,链接: https://pan.baidu.com/s/1CY0xQq3GLK06iX7tVLnp3Q 提取码: ...

  2. QT 中 关键字讲解(emit,signal,slot)

    Qt中的类库有接近一半是从基类QObject上继承下来,信号与反应槽(signals/slot)机制就是用来在QObject类或其子类间通讯的方法.作为一种通用的处理机制,信号与反应槽非常灵活,可以携 ...

  3. QT中的线程与事件循环理解(1)

    1.需要使用多线程管理的例子 一个进程可以有一个或更多线程同时运行.线程可以看做是“轻量级进程”,进程完全由操作系统管理,线程即可以由操作系统管理,也可以由应用程序管理.Qt 使用QThread 来管 ...

  4. python中如何统计一个类的实例化对象

    类中的静态变量 需要通过类名.静态变量名 来修改 :通过对象不能修改 python中如何统计一个类的实例化对象?? class Person: #静态变量count,用于记录类被实例化的次数 coun ...

  5. [转]ThinkPHP中实例化对象M()和D()的区别,select和find的区别

    1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法实例化模型无需用户为每个数据表定义模型类,如果D方法没有找到定义的模型类,则会 ...

  6. 1、c#中可以有静态构造方法,而java中没有,例如在单例模式中c#可以直接在静态构造中实例化对象,而java不可以

    1.c#中可以有静态构造方法,而java中没有,例如在单例模式中c#可以直接在静态构造中实例化对象,而java不可以

  7. ThinkPHP中实例化对象M()和D()的区别,select和find的区别

    原文:ThinkPHP中实例化对象M()和D()的区别,select和find的区别 1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在 ...

  8. spring中获取dao或对象中方法的实例化对象

    spring中获取dao的中方法的实例化对象: //获取应用上下文对象 ApplicationContext ctx = new ClassPathXmlApplicationContext(&quo ...

  9. javascript中使用new与不使用实例化对象的区别

    我们先来看个实例 function Me(name,age,job){ this.name = name; this.age = age; this.job = job; } 请问这以下两种实例化对象 ...

随机推荐

  1. Atitit  项目界面h5化静态html化计划---vue.js 把ajax获取到的数据 绑定到表格控件 v2 r33.docx

    Atitit  项目界面h5化静态html化计划---vue.js 把ajax获取到的数据 绑定到表格控件 v2 r33.docx 1. 场景:应用在项目列表查询场景下1 1.1. 预计初步掌握vue ...

  2. x86-64整数寄存器

  3. android使用百度地图SDK 去掉百度Logo的小技巧

    // 隐藏logoView child = mMapView.getChildAt(1); if (child != null && (child instanceof ImageVi ...

  4. log_output参数是指定日志的存储方式

    log_output='FILE'表示将日志存入文件,默认值是'FILE' log_output='TABLE'表示将日志存入数据库,这样日志信息就会被写入到mysql.slow_log表中. mys ...

  5. 使用putty部署远程J2EE环境

    以前没弄过,开个帖子记录一下. 基本上要做的就是安装JDK.安装tomcat.安装sql. 1.安装JDK JDK在本机上,需要传输到远程linux服务器上.为了存放我们上传的文件.打开putty,进 ...

  6. socket.io笔记二之事件监听回调函数接收一个客户端的回调函数

    //服务端 socket.on('test', function (name, fn) { console.log(name) //输出yes fn('woot'); }); //客户端 socket ...

  7. 2-2-求并集A=A∪B-线性表-第2章-《数据结构》课本源码-严蔚敏吴伟民版

    课本源码部分 第2章  线性表 - 求并集A=A∪B ——<数据结构>-严蔚敏.吴伟民版        ★有疑问先阅读★ 源码使用说明  链接☛☛☛ <数据结构-C语言版>(严 ...

  8. linux怎么关闭iptables linux如何关闭防火墙

    Linux系统下面自带了防火墙iptables,iptables可以设置很多安全规则.但是如果配置错误很容易导致各种网络问题,那么如果要关闭禁用防火墙怎么操作呢,咗嚛本经验以centos系统为例演示如 ...

  9. 解决最小化安装Centos7后无法上网的问题,以及安装成功后的基本配置

    发现问题 刚装完最小化的系统后,如果直接ping外网,可能回出现如下情况 解决问题 首先编辑虚拟机的DHCP池: 在弹出的“虚拟网络编辑器”窗口中选择NAT模式的,编辑为其分配地址池: 然后编辑网卡的 ...

  10. CSAPP 读书笔记 - 2.31练习题

    根据等式(2-14) 假如w = 4 数值范围在-8 ~ 7之间 2^w = 16 x = 5, y = 4的情况下面 x + y = 9 >=2 ^(w-1)  属于第一种情况 sum = x ...