QT 反射机制

来源:互联网 发布:淘宝手机店铺切图模块 编辑:程序博客网 时间:2024/05/12 00:39
#ifndef MYOBJ_H#define MYOBJ_H#include <QObject>#include <qstring.h>class MyObj : public QObject{    Q_OBJECT    Q_PROPERTY(int ww READ id WRITE setid)    Q_PROPERTY(QString m_strName READ name WRITE setName)public:    explicit MyObj(QObject *parent = 0);    Q_INVOKABLE int id();    Q_INVOKABLE void setid(int);    Q_INVOKABLE QString name();    Q_INVOKABLE void setName(QString);signals:public slots:private:    int m_nId;    QString m_strName;};#endif // MYOBJ_H
</pre><pre code_snippet_id="1971431" snippet_file_name="blog_20161107_7_6978204" name="code" class="cpp">
<pre style="margin-top: 0px; margin-bottom: 0px;"><span style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"myobj.h"</span>
MyObj::MyObj(QObject *parent) : QObject(parent)
{
    m_nId = 0;
}
int MyObj::id()
{
    return m_nId;
}
void MyObj::setid(int nid)
{
    m_nId = nid;
}
QString MyObj::name()
{
    return m_strName;
}
void MyObj::setName(QString str)
{
    m_strName = str;
}
<pre name="code" class="plain">简介本文主要讲解Qt是如何实现反射,以及一点点反射使用的小心得。文章概览Qt反射内幕小窥详细内容反射前期准备得到注册的类成员变量得到注册的类成员函数访问类成员属性(get,set)调用注册的函数反射应用总结Qt反射内幕小窥Qt反射机制是基于moc(meta object compiler)实现的,在这里多插一句(可以说Qt所有C++没有的特性,几乎都和这个有关系)。但是需要注意的是Qt提供的反射式基本的反射,不支持类的反射,这个与Java,C#还是有差别的。moc讲解通常C++的编译过程为预处理->编译->链接->运行Qt编译的过程中,有一个moc的过程,在Qt工程构建过程中的qmake其实就是干这个事的。moc->预处理->编译->链接->运行。在moc过程中,需要处理的事情如下:1、 识别一些特殊的宏Q_OBJECT、Q_PROPERTY、Q_INVOKABLE。。。; 如果碰到这些关键字,Qt自然就会去生成对应的moc文件。2、 slot,signal自然也是如此。3、 uidesigner,同样也是在这个阶段处理的;详细内容 反射前期准备1、 首先得继承于Q_Object,同时需要在class中加入Q_OBJECT,但是Q_Object的构造函数默认是私有的不让继承。在类中直接使用Q_GADGET也可以实现反射,。。。据说只能实现部分功能,目前我只实现到能遍历成员属性,函数,但是不能访问其中的值。这个过程其实就是定义QMetaObject的过程,具体见Qt源码2、 注册类成员变量需要使用Q_PROPERTYQ_PROPERTY( type member READ get WRITE set) 其中READ,WRITE是关键字Type表示成员的类型(不支持自定义类型,对Qt很多基本类型都支持);Member代表你给该成员另外起的名字,可以和变量名不同;get,set就是自己在C++函数里面定义的基本的访问函数名,不需要写参数。直接上代码:3、 注册类成员函数如果你希望这个函数能够被反射,那么很简单,只需要在类的函数声明前加入Q_INVOKABLE关键字。例如Q_INVOKABLE int func( QString flag );   #include <QObject>   class MyClass : public QObject   {    Q_OBJECT    Q_PROPERTY(int Member1 READ Member1 WRITE setMember1 )    Q_PROPERTY(int Member2 READ Member2 WRITE setMember2 )    Q_PROPERTY(QString MEMBER3 READ Member3 WRITE setMember3 )   public:    explicit MyClass(QObject *parent = 0);   signals:   public slots:   public:    Q_INVOKABLE int Member1();    Q_INVOKABLE int Member2();    Q_INVOKABLE QString Member3();    Q_INVOKABLE void setMember1( int mem1 );    Q_INVOKABLE void setMember2( int mem2 );    Q_INVOKABLE void setMember3( const QString& mem3 );    Q_INVOKABLE int func( QString flag );   private:    int m_member1;    int m_member2;    QString m_member3;   };得到注册的类成员变量  MyClass theObj; const QMetaObject* metaObj = theObj.metaObject(); //1.遍历类的属性 int propertyCnt = metaObj->propertyCount(); for ( int i = 0; i < propertyCnt; ++ i ) { QMetaProperty oneProperty = metaObj->property( i ); cout << " name: " << oneProperty.name(); cout << " type: " << QVariant::typeToName( oneProperty.type()) << "\n";  }主要思路就是得到其元对象,得到其元属性,然后就能得到你需要的信息,具体的访问函数有name,type,需要注意的是得到的type是枚举值,还在Qt提供了typeToName的函数,你可以得到想要的(例如不是空洞的2,而是”int”)。得到注册的类成员函数//2.遍历类的函数成员 int methodCnt = metaObj->methodCount(); for ( int idx = 0; idx < methodCnt; ++ idx ) { QMetaMethod oneMethod = metaObj->method( idx ); cout << "--------begin-------" << "\n"; cout << " typeName: " << oneMethod.typeName() << "\n"; cout << " signature: " << oneMethod.signature() << "\n"; cout << " methodType: " << oneMethod.methodType() << "\n"; cout << "--------end---------" << "\n";  }和遍历类属性一致,其实就是根据元对象,得到元函数;其中typeName代表返回类型,signature只的是函数的原貌,methodType代表函数的类型,在Qt中分为三类(槽,信号,普通函数)。访问类成员属性(get,set)//3.使用反射 cout << "-------test property-----------" << "\n"; MyClass newObj; newObj.setProperty("Member1", 66); cout << newObj.property( "Member1" ).toString().toStdString() << "\n"; cout << newObj.Member1() << "\n"; cout << "--------end----------" << "\n";在这里使用的是QObject的property() 和setProperty方法,来访问成员信息。但是对于使用Q_GADGET宏的类,是不能使用这个方法的,还在寻找解决方法,基本思路当然是重写。调用注册的函数  int ret;  MyClass newObj; newObj.setMember1( 20 ); newObj.setMember2( 50 ); QMetaObject::invokeMethod( &newObj, "func", Qt::DirectConnection, Q_RETURN_ARG(int, ret ), Q_ARG(QString, "+"));//普通函数的调用在MyClass中,我们定义了int func( QString flag );这个函数,利用反射的调用方式如上,主要是理解invokeMethod的用法,其中Qt::DirectConnection是函数的执行方式,分为(异步和同步),Q_RETURN_ARG是返回参数,Q_ARG是传入参数,需要按函数声明中参数的顺序依次传入,Qt最多支持9个参数,对于一般的应用没有问题。还有疑问,请移步具见Qt强大的帮助文档。反射的应用反射反射,就我目前的认知水平来看,通过使用字符串,来实现函数的通用化调用,例如你可以利用反射把很多函数放置到数组中,实现一次遍历,全部调用。目前我见到的大多是利用反射来操作数据库,例如hibernate,其实可以利用Qt的反射,快速实现所谓的hibernate,(最近自己独立实现了一套,很方便)。


</pre><pre code_snippet_id="1971431" snippet_file_name="blog_20161107_7_6978204" name="code" class="cpp">


0 0
原创粉丝点击