Qt反射

简介

本文主要讲解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_PROPERTY

Q_PROPERTY( type member READ get WRITE set) 其中READ,WRITE是关键字

Type表示成员的类型(不支持自定义类型,对Qt很多基本类型都支持);

Member代表你给该成员另外起的名字,可以和变量名不同;get,set就是自己在C++函数里面定义的基本的访问函数名,不需要写参数。直接上代码:

3、 注册类成员函数

如果你希望这个函数能够被反射,那么很简单,只需要在类的函数声明前加入Q_INVOKABLE关键字。

例如Q_INVOKABLE int func( QString flag );

 1 #include <QObject>
 2    class MyClass : public QObject
 3    {
 4     Q_OBJECT
 5     Q_PROPERTY(int Member1 READ Member1 WRITE setMember1 )
 6     Q_PROPERTY(int Member2 READ Member2 WRITE setMember2 )
 7     Q_PROPERTY(QString MEMBER3 READ Member3 WRITE setMember3 )
 8    public:
 9     explicit MyClass(QObject *parent = 0);
10    signals:
11    public slots:
12    public:
13     Q_INVOKABLE int Member1();
14     Q_INVOKABLE int Member2();
15     Q_INVOKABLE QString Member3();
16     Q_INVOKABLE void setMember1( int mem1 );
17     Q_INVOKABLE void setMember2( int mem2 );
18     Q_INVOKABLE void setMember3( const QString& mem3 );
19     Q_INVOKABLE int func( QString flag );
20    private:
21     int m_member1;
22     int m_member2;
23     QString m_member3;
24    }; 

得到注册的类成员变量

 1  MyClass theObj;
 2  const QMetaObject* metaObj = theObj.metaObject();
 3  //1.遍历类的属性
 4  int propertyCnt = metaObj->propertyCount();
 5  for ( int i = 0; i < propertyCnt; ++ i )
 6  {
 7  QMetaProperty oneProperty = metaObj->property( i );
 8  cout << " name: " << oneProperty.name();
 9  cout << " type: " << QVariant::typeToName( oneProperty.type()) << "\n";
10   }

主要思路就是得到其元对象,得到其元属性,然后就能得到你需要的信息,具体的访问函数有name,type,需要注意的是得到的type是枚举值,还在Qt提供了typeToName的函数,你可以得到想要的(例如不是空洞的2,而是”int”)。

得到注册的类成员函数

 1 //2.遍历类的函数成员
 2  int methodCnt = metaObj->methodCount();
 3  for ( int idx = 0; idx < methodCnt; ++ idx )
 4  {
 5  QMetaMethod oneMethod = metaObj->method( idx );
 6  cout << "--------begin-------" << "\n";
 7  cout << " typeName: " << oneMethod.typeName() << "\n";
 8  cout << " signature: " << oneMethod.signature() << "\n";
 9  cout << " methodType: " << oneMethod.methodType() << "\n";
10  cout << "--------end---------" << "\n";
11   }

和遍历类属性一致,其实就是根据元对象,得到元函数;

其中typeName代表返回类型,signature只的是函数的原貌,methodType代表函数的类型,在Qt中分为三类(槽,信号,普通函数)。

访问类成员属性(get,set)

1 //3.使用反射
2  cout << "-------test property-----------" << "\n";
3  MyClass newObj;
4  newObj.setProperty("Member1", 66);
5  cout << newObj.property( "Member1" ).toString().toStdString() << "\n";
6  cout << newObj.Member1() << "\n";
7  cout << "--------end----------" << "\n";

在这里使用的是QObject的property() 和setProperty方法,来访问成员信息。但是对于使用Q_GADGET宏的类,是不能使用这个方法的,还在寻找解决方法,基本思路当然是重写。

调用注册的函数

1  int ret;
2  MyClass newObj;
3  newObj.setMember1( 20 );
4  newObj.setMember2( 50 );
5  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,(最近自己独立实现了一套,很方便)。

总结

这篇文章主要讲了如何使用Qt来实现反射,在实用角度上来讲,我们不需要了解Qt是怎么实现反射的,对于怎么用上面说的很清楚了。

转自:http://www.cppblog.com/Cunch/archive/2013/07/13/201779.html

时间: 2024-11-05 13:26:58

Qt反射的相关文章

Qt5只反射机制(内省)

Qt的元对象系统除了提供信号/槽机制的特性之外,它还提供了以下特性: QObject::metaObject() 返回关联的元对象 QMetaObject::className() 在运行时状态下返回类名 QObject::inherits() 判断类的继承关系 QObject::tr(),QObject::trUtf8() 提供国际化,翻译字符串 QObject::setProperty(),QObject::property() 通过名称来动态设置和获取属性 QMetaObject::new

Qt编写自定义控件属性设计器

以前做.NET开发中,.NET直接就集成了属性设计器,VS不愧是宇宙第一IDE,你能够想到的都给你封装好了,用起来不要太爽!因为项目需要自从全面转Qt开发已经6年有余,在工业控制领域,有一些应用场景需要自定义绘制一些控件满足特定的需求,比如仪器仪表.组态等,而且需要直接用户通过属性设计的形式生成导出控件及界面数据,下次导入使用,要想从内置控件或者自定义控件拿到对应的属性方法等,首先联想到的就是反射,Qt反射对应的类叫QMetaObject,着实强大,其实整个Qt开发框架也是超级强大的,本人自从转

Qt and C++ Reflection,利用Qt简化C++的反射实现

如何在C++中实现反射机制,应该算是C++开发中经常遇到的问题之一.C++程序没有完整的元数据,也就无法实现原生的反射机制.从性能的角度讲,这样的设计不难理解,毕竟在运行时储存这些元数据需要额外的开销.不为你不使用的东西付出代价,这是C++的哲学,所以当我们需要反射机制时,我们得自己来实现它.所幸如今各种C++的反射实现已经相当成熟,比如boost::reflect,以及本文所使用的Qt. Qt是常见的C++跨平台应用程序框架之一,除了用于开发GUI程序之外,Qt本身也是一套完整的C++库.不同

Qt根据类获取对象(元对象反射)

在java语言中,可以使用getObject(String)函数,从类型直接构建新的对象. 而在C++中是没有这种机制的,Qt虽然提供了元对象机制,但只可以获取对象的类名,不能反向构建. 这个问题我在百度上找了很多,但都没有满意的答案,索性翻出去google一下,终于找到了解决方法. 原文地址:http://www.mimec.org/node/350 代码如下: objectfactory.h #include <QByteArray> #include <QMetaObject>

Qt元对象(Meta-Object)系统与反射

反射 -在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问.检测和修改它本身状态或行为的一种能力.[1]用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为. 要注意术语“反射”和“内省”(type introspection)的关系.内省(或称“自省”)机制仅指程序在运行时对自身信息(称为元数据)的检测:反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构. C++的反射 C++的标准语法是不提供反射的特性的,不

Qt 3D的研究(五):Gooch Shader

Qt 3D的研究(五):Gooch Shader Qt 3D的一个很大的优势就是采用数据驱动的方式,将C++和GLSL使用QML来表示,动态语言的优势尽显.在上一次的研究中,我实现了一个非常简单的着色器,接下来,我们可以在此基础上,通过设定着色器的数据,制作出更加绚丽的着色效果.作为开始,我们先从几个非真实渲染(Non-Photorealistic Rendering,NPR)开始吧. 蒋彩阳原创文章,首发地址:http://blog.csdn.net/gamesdev/article/deta

QT中的线程与事件循环理解(2)

1. Qt多线程与Qobject的关系 每一个 Qt 应用程序至少有一个事件循环,就是调用了QCoreApplication::exec()的那个事件循环.不过,QThread也可以开启事件循环.只不过这是一个受限于线程内部的事件循环.因此我们将处于调用main()函数的那个线程,并且由QCoreApplication::exec()创建开启的那个事件循环成为主事件循环,或者直接叫主循环.注意,QCoreApplication::exec()只能在调用main()函数的线程调用.主循环所在的线程

QObject提供了QMetaObject元类信息(相当于RTTI和反射),信号与连接,父子关系,调试信息,属性,事件,继承关系,窗口类型,线程属性,时间器,对象名称,国际化

元类信息(相当于RTTI和反射),信号与连接,父子关系,调试信息,属性,事件,继承关系,窗口类型,线程属性,时间器,对象名称,国际化其中元类又提供了:classInfo,className,构造函数,多重祖先元类,method, property, Enumerator, Signal, Slot等等 http://doc.qt.io/qt-5/qobject.html http://doc.qt.io/qt-5/qmetaobject.html 我感觉Qt的出现,除了提供GUI以外,主要就是提

元对象、 属性 和 反射编程

所谓反射,就是指对象成员的自我检查,使用反射编程就可以编写出通用的操作,可对具有各种不同结构的类进行操作; Qt使用通用的值存储器QVariant,就可以按照一种统一的方式来对基本类型和其他普通类型进行操作; QMetaObject  ---- 元对象模式 元对象,就是描述另一个对象结构的对象; QMetaObject是元对象模式(MetaObject Pattern)的一个Qt实现,他提供一个QObject对象拥有的属性和方法的信息.      一个拥有元对象的类就可以支持反射,这是一个许多面