本文共 3343 字,大约阅读时间需要 11 分钟。
Qt的信号槽和属性系统基于在运行时进行内省的能力,所谓内省是指面向对象语言的一种在运行期间查询对象信息的能力。C++的内省比较有限,仅支持型别内省,C++的型别内省是通过运行时类型识别(RTTI)中的typeid和dynamic_cast关键字来实现的。Qt拓展了C++的内省机制,但并没有采用C++的RTTI,而是提供了更为强大的元对象(Meta Object)机制,来实现内省机制。基于内省机制,可以列出对象的方法和属性列表,并且能够获取有关对象的所有信息,如参数类型。如果没有内省机制,QtScript和QML是难以实现的。
Qt中的元对象系统全称Meta Object System,是一个基于标准C++的扩展,为Qt提供了信号与槽机制、实时类型信息、动态属性系统。元对象系统基于QObject类、Q_OBJECT宏、元对象编译器MOC实现。
QObject是每一个需要利用元对象系统的类的基类。任何从QObject继承的类都可以利用元对象系统提供的功能。
Q_OBJECT宏定义在每一个类的私有数据段,用来启用元对象功能,比如动态属性、信号和槽。在一个QObject类或者其派生类中,如果没有声明Q_OBJECT宏,那么类的metaObject()返回的就是其父类的metaObject(),导致的后果是从类的实例获得的元数据其实都是父类的数据。因此,任何从QObject继承出来的类,无论是否定义声明了信号、槽和属性,都应该声明Q_OBJECT宏。
MOC(Meta Object Complier,元对象编译器)分析C++源文件,如果发现一个头文件中包含Q_OBJECT宏定义,会动态生成一个moc_xxxx命名的C++源文件,包含Q_OBJECT的实现代码,会被编译、链接到类的二进制代码中,作为类的完整的一部分。
Q_OBJECT宏定义在src/corelib/kernel/Qobjectdefs.h文件中。任何从QObject派生的类都包含自己的元数据模型,一般通过宏Q_OBJECT定义。
QMetaObject类定义在src/corelib/kernel/Qobjectdefs.h文件。QMetaObject中有一个嵌套结构封装了所有的数据:
superdata:元数据代表的类的基类的元数据stringdata:元数据的签名标记data:元数据的索引数组的指针extradata:扩展元数据表的指针,指向QMetaObjectExtraData数据结构QT_TR_FUNCTIONS宏定义与翻译相关。宏定义如下:
static inline QString tr(const char *s, const char *c = 0) { return staticMetaObject.tr(s, c);} 这个宏定义用于翻译字符串,使用静态方法tr()来实现。
Qt在src/corelib/kernel/Qobjectdefs.h文件中定义了大量的宏。这些宏大部分用于MOC工具解析和处理,具体包括:
Q_SLOTS、Q_SIGNALS、Q_PRIVATE_SLOT、Q_EMIT等用于信号和槽的定义Q_CLASSINFO、Q_INTERFACES、Q_PROPERTY、Q_PRIVATE_PROPERTY、Q_REVISION、Q_ENUMS、Q_FLAGS、Q_SCRIPTABLE、Q_INVOKABLE、Q_SIGNAL、Q_SLOT等用于元数据的定义和扩展这些宏定义无实际的代码扩展作用,都是为了MOC工具解析和处理。
在工程的Makefile文件中可以查找到MOC生成moc_xxx.cpp文件的命令。例如:
moc Object.cpp -o moc_Object.cpp
MOC工具根据类的元数据定义,自动生成相关的代码。
MOC主要功能包括:
Q_OBJECT宏和signals/slots关键字,生成信号和槽的底层代码Q_PROPERTY()和Q_ENUM(),生成属性系统和枚举类型的代码Q_FLAGS()和Q_CLASSINFO(),生成额外的类元数据信息#ifndef Q_MOC_RUN// 不需要MOC处理的代码#endif
MOC有一些限制:
connect时的信号和槽名称和参数QObject(或其子类)作为多重继承的父类时,必须放在第一个typedef的类型做信号和槽的参数时,必须使用完全限定语法在Qt中,自定义类型如果直接使用信号槽来传递,会产生错误:
QObject::connect: Cannot queue arguments of type 'XXXXX' (Make sure 'XXXXX' is registered using qRegisterMetaType())
原因是信号参数需要被拷贝存储在队列中,Qt需要知道如何处理这些类型。解决方法是:
#include <QMetaType>Q_DECLARE_METATYPE(XXXXX)main()函数中注册类型:qRegisterMetaType<XXXXX>("XXXXX")qRegisterMetaType<XXXXX>("XXXXX&")在Main.cpp中,可以看到MOC生成的代码:
#include#include "Object.h"int main(int argc, char *argv) { QCoreApplication a(argc, argv); Object ob("object"); ob.setProperty("age", QVariant(30)); qDebug() << "age: " << ob.age(); qDebug() << "property age: " << ob.property("age").toInt(); ob.setProperty("score", QVariant(90)); qDebug() << "score: " << ob.score(); qDebug() << "property score: " << ob.property("score").toInt(); // 内省 qDebug() << "object name: " << ob.objectName(); qDebug() << "class name: " << ob.metaObject()->className(); qDebug() << "isWidgetType: " << ob.isWidgetType(); qDebug() << "inherit: " << ob.inherits("QObject"); return a.exec();}
通过上述步骤,可以看出MOC生成的代码包含了元对象系统的实现细节。
转载地址:http://iuxfk.baihongyu.com/