Qt Meta Object System-元对象系统

摘要:
元对象系统QObject的组成为需要使用元对象系统的所有对象提供了一个基类。MetaObjectCompiler,它为每个QObject派生类生成代码,以支持元对象函数。QObject和QMetaObjectQMeta对象包含所谓的QObject元数据,即QObject信息的一些描述信息:除了类型信息,它还包含QT中的特定信号和时隙信息。这样,当通过QObject类型的引用调用metaObejct方法时,将返回引用所引用的实际对象的元对象。这样,每个QObject类都有一个对应的QMetaObject类,形成了一个并行类型层次结构。例如,MOSTestObject继承了QObject并定义了两个属性:PropertyA和PropertyB;两类信息:作者,版本;枚举:TestEnum。

研一的时候开始使用Qt,感觉用Qt开发图形界面比MFC的一套框架来方便的多。后来由于项目的需要,也没有再接触Qt了。现在要重新拾起来,于是要从基础学起。

Now,开始学习Qt事件处理机制。

元对象系统的构成

  1. QObject为所有需要利用元对象系统的对象提供一个基类。
  2. Q_OBJECT宏,在类的声明体内激活meta-object功能,比如动态属性、信号和槽。
  3. Meta Object Compiler(MOC),为每个QObject派生类生成代码,以支持meta-object功能。
  4. QObject定义了从一个QObject对象访问meta-object功能的接口,Q_OBJECT宏用来告诉编译器该类需要激活meta-object功能,编译器在扫描一个源文件时,如果发现类的声明中有这个宏,就会生成一些代码来为支持meta-object功能——主要是生成该类对应MetaObject类以及对QObject的函数override(重载)。

QObject和QMetaObject

QMetaObject包含了QObject的所谓的元数据,也就是QObject信息的一些描述信息:除了类型信息外,还包含QT中特有的signal&slot信息。

virtual QObject::metaObject();

该方法返回一个QObject对应的metaObject对象,如上文所说,如果一个类的声明中包含了Q_OBJECT宏,编译器会生成代码来实现这个类对应的QMetaObject类,并重载QObject::metaObject()方法来返回这个QMetaObject类的实例引用。这样当通过QObject类型的引用调用metaObejct方法时,返回的是这个引用的所指的真实对象的metaobject。

如果一个类从QObject派生,确没有声明Q_OBJECT宏,那么这个类的metaobject对象不会被生成,这样这个类所声明的signal slot都不能使用,而这个类实例调用metaObject()返回的就是其父类的metaobject对象,这样导致的后果就是你从这个类实例获得的元数据其实都是父类的数据,这显然给你的代码埋下隐患。因此如果一个类从QOBject派生,它都应该声明Q_OBJECT宏,不管这个类有没有定义signal&slot和Property。

这样每个QObject类都有一个对应的QMetaObject类,形成一个平行的类型层次。

QMetaObject提供的信息

下面通过QMetaObject的接口来解释QMetaObject提供的信息。

1)基本信息

structQ_CORE_EXPORT QMetaObject
{
       const char *className() const;
       const QMetaObject *superClass() const;
     struct { // private data
const QMetaObject *superdata; //父类QMetaObject实例的指针 const char *stringdata; //一段字符串内存块,包含MetaObject信息之字符串信息 const uint *data; //一段二级制内存块,包含MetaObject信息之二进制信息 const void *extradata; //额外字段,暂未使用 } d;
...
};

2)classinfo:提供额外的类信息-名值对。用户可以在类的生命中以Q_CLASSINFO(name,value)的方式添加。

 int classInfoOffset() const;
 int classInfoCount() const;
 int indexOfClassInfo(const char *name) const;
 QMetaClassInfo classInfo(int index) const;

example:

class MyClass : publicQObject
{
    Q_OBJECT
    Q_CLASSINFO("author", "Sabrina Schweinsteiger")
    Q_CLASSINFO("url", "http://doc.moosesoft.co.uk/1.0/")
public:
    ...
};

3)constructor:提供该类的构造方法信息。

 int constructorCount() const;
 int indexOfConstructor(const char *constructor) const;
 QMetaMethod constructor(int index) const;

4)enum:描述该类声明体重所包含的枚举类型信息。

 int enumeratorOffset() const;
 int enumeratorCount() const;
 int indexOfEnumerator(const char *name) const;
 QMetaEnum enumerator(int index) const;

5)method:描述类中所包含方法信息:包括property,signal,slot等。

 int methodOffset() const;
 int methodCount() const;
 int indexOfMethod(const char *method) const;
 int indexOfSignal(const char *signal) const;
 int indexOfSlot(const char *slot) const;
 QMetaMethod method(int index) const;

6)property:类型的属性信息。

 int propertyOffset() const;
 int propertyCount() const;
 int indexOfProperty(const char *name) const;
 QMetaProperty property(int index) const;

注意:对于类里面定义的函数,构造函数,枚举,只有加上一些宏才表示你希望为方法提供meta信息。比如 Q_ENUMS用来注册宏,Q_INVACABLE用来注册方法(包括构造函数)。Qt这么设计的原因应该是避免meta信息的臃肿。

举例说明MOS(Meta Object System)

TestObject继承QObject,定义了两个Property:PropertyA和PropertyB;两个classinfo:Author,version;一个枚举:TestEnum。

    #include <QObject>  
    class TestObject : publicQObject  
    {  
        Q_OBJECT  
        Q_PROPERTY(QString propertyA  READ getPropertyA WRITE getPropertyA RESET resetPropertyA DESIGNABLE true SCRIPTABLE true STORED true USER false)  
        Q_PROPERTY(QString propertyB  READ getPropertyB WRITE getPropertyB RESET resetPropertyB)  
        Q_CLASSINFO("Author", "Long Huihu")  
        Q_CLASSINFO("Version", "TestObjectV1.0")  
        Q_ENUMS(TestEnum)  
    public:  
        enumTestEnum {  
            EnumValueA,  
            EnumValueB  
        };  
    public:  
        TestObject();  
    signals:  
        voidclicked();  
        voidpressed();  
    publicslots:  
        void onEventA(const QString &);  
        void onEventB(int);  
    }

TestObject的moc文件:

#include "TestObject.h"  
    #if !defined(Q_MOC_OUTPUT_REVISION)  
    #error "The header file 'TestObject.h' doesn't include <QObject>."  
    #elif Q_MOC_OUTPUT_REVISION != 62  
    #error "This file was generated using the moc from 4.6.0. It"  
    #error "cannot be used with the include files from this version of Qt."  
    #error "(The moc has changed too much.)"  
    #endif  
    QT_BEGIN_MOC_NAMESPACE  
    static const uint qt_meta_data_TestObject[] ={  
     //content:  
           4,       //revision  
           0,       //classname  
           2,   14, //classinfo  
           4,   18, //methods  
           2,   38, //properties  
           1,   44, //enums/sets  
           0,    0, //constructors  
           0,       //flags  
           2,       //signalCount  
     //classinfo: key, value  
          22,   11,  
          44,   29,  
     //signals: signature, parameters, type, tag, flags  
          53,   52,   52,   52, 0x05,  
          63,   52,   52,   52, 0x05,  
     //slots: signature, parameters, type, tag, flags  
          73,   52,   52,   52, 0x0a,  
          91,   52,   52,   52, 0x0a,  
     //properties: name, type, flags  
         113,  105, 0x0a095007,  
         123,  105, 0x0a095007,  
     //enums: name, flags, count, data  
         133, 0x0,    2,   48,  
     //enum data: key, value  
         142, uint(TestObject::EnumValueA),  
         153, uint(TestObject::EnumValueB),  
           0        //eod  
};  
    static const char qt_meta_stringdata_TestObject[] ={  
        "TestObject

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇springboot mybatis自定义枚举enum转换win7下JAVA环境变量配置方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ModelContext模型上下文

usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Web;   namespaceTeamService.Data {     publicclassModelContextStatus     {         publicconstintDISAB...

Ansi,UTF8,Unicode编码(续)

1.三种编码的回顾 Ansi字符串我们最熟悉,英文占一个字节,汉字2个字节,以一个\0结尾,常用于txt文本文件。 Unicode字符串,每个字符(汉字、英文字母)都占2个字节;在VC++的世界里,Microsoft比较鼓励使用Unicode,如wchar_t。 UTF8是Unicode一种压缩形式,英文A在unicode中表示为0x0041,英语中这种存...

C++编译遇到参数错误(cannot convert parameter * from 'const char [**]' to 'LPCWSTR')

转:http://blog.sina.com.cn/s/blog_9ffcd5dc01014nw9.html 前面的几天一直都在复习着被实习落下的C++基础知识。今天在复习着上次创建的窗口程序时,出现了一个错误,百思不得其解。因为是同样的代码,上次的都能顺利的通过编译,这次自己新建了一个工程结果就有一个错误出现,是在调用Create()函数时,传参数出现问...

openbmc工程概述

下载 git clone https://github.com/openbmc/openbmc.git 目录概述 openbmc工程目录主要包含 meta-{vendor} vedor: amd,arm,aspeed,facebook,ibm... meta-phosphor meta-openpower poky meta-openembedded...

UNIX网络编程——网络IPC:套接字

Contents 套接字接口 套接字描述符 寻址 字节序 地址格式 地址查询 绑定地址 建立连接 数据传输 套接字选项 带外数据 UNIX域套接字 使用套接字的示例 面向连接的ruptime 无连接的ruptime 套接字接口       套接字接口是一组用来结合UNIX I/O函数进行进程间通信的函数,大多数系统上都实现了它,包括各...

hwclock和date源码分析

一. hwclock 1.1 hwclock源码在哪里? util-linux 或者busybox 1.2 获取源码 git clone https://github.com/karelzak/util-linux.git 或 git clonegit://git.busybox.net/busybox 1.3 hwclock的源码路径 sys-utils...