zoukankan      html  css  js  c++  java
  • Qt中如何根据类名来实例化对象

    对于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


  • 相关阅读:
    winform窗体扁平化设置,窗体移动,关闭
    WPF按钮控件模板
    C#连接Sqlite报错:{"试图加载格式不正确的程序。 (异常来自 HRESULT:0x8007000B)"}
    C#SQLite使用教程笔记
    C#自定义控件导航菜单(自定义事件,属性)
    LCS局域网屏幕监控系统安装指导
    System.Data.SQLite.dll 未安装或者版本冲突,按下面步骤操作即可 1、从Nuget卸载所有项目的System.Data.SQLite.dll 和SqlSugar,检查引用中是否还存在,存在直接删掉引用,然后Nuget重新安装即可
    C#项目脱落NuGet
    JavaScript跨域总结与解决办法
    回流与重绘:CSS性能让JavaScript变慢?
  • 原文地址:https://www.cnblogs.com/liushui-sky/p/6559973.html
Copyright © 2011-2022 走看看