`
美丽的小岛
  • 浏览: 312275 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

[转—QT]moc生成文件分析

    博客分类:
  • QT
 
阅读更多

首先看一下简单含有的signal, slot代码

  1. class myClass : public QObject  
  2. {  
  3.     Q_OBJECT  
  4. public:  
  5.     myClass();  
  6.     ~myClass();  
  7.     void trigger();  
  8.     void trigger2();  
  9. signals:  
  10.         void signalFunc(double);  
  11.         int signalFunc2(charint);  
  12. protected slots:  
  13.         void slotFunc(double);  
  14.         int slotFunc2(char);  
  15. };  
  16. // 只是实例代码,用来生成moc_myClass  
  17. #include"myClass.h"  
  18. #include<iostream>  
  19. using std::cout;  
  20. using std::endl;  
  21. myClass::myClass()  
  22. {  
  23.     connect(this, SIGNAL(signalFunc),  
  24.             this, SLOT(slotFunc));  
  25.     connect(this, SIGNAL(signalFunc2),  
  26.             this, SLOT(slotFunc2));  
  27. }  
  28. myClass::~myClass()  
  29. {  
  30. }  
  31. void myClass::slotFunc(double d)  
  32. {  
  33.     cout << "slotFunc" << endl;  
  34. }  
  35. int myClass::slotFunc2(char c)  
  36. {  
  37.     cout << "slotFunc2" << endl;  
  38.     return c;  
  39. }  
  40. void myClass::trigger()  
  41. {  
  42. }  
  43. void myClass::trigger2()  
  44. {  
  45. }   

编译生成moc_myClass.cpp

 

  1. static const uint qt_meta_data_myClass[] = {  
  2.  // content:  
  3.        4,       // revision  
  4.        0,       // classname  
  5.        0,    0, // classinfo  
  6.        4,   14, // methods  
  7.        0,    0, // properties  
  8.        0,    0, // enums/sets  
  9.        0,    0, // constructors  
  10.        0,       // flags  
  11.        2,       // signalCount  
  12.  // signals: signature, parameters, type, tag, flags  
  13.        9,    8,    8,    8, 0x05,  
  14.       34,   32,   28,    8, 0x05,  
  15.  // slots: signature, parameters, type, tag, flags  
  16.       56,    8,    8,    8, 0x09,  
  17.       73,    8,   28,    8, 0x09,  
  18.        0        // eod  
  19. };  

 其中methods部分,4代表这个对象含有4个signal + slot, 14是基础数字,在moc代码里面也是硬编码,数一下content的个数,刚好是14,这个14其实就是个偏移量,偏移到signal的第一行

signal和slot的flag提供了一些属性,这个会在后面的QObject::connect讲到。

这里需要提出来一点是signal和slot的第一个数值,9, 34, 56, 73这几个,这个马上会讲到先提出来,留个印象

这里前14个数值是对应的QMetaObjectPrivate的值

 

  1. struct QMetaObjectPrivate  
  2. {  
  3.     int revision;  
  4.     int className;  
  5.     int classInfoCount, classInfoData;  
  6.     int methodCount, methodData;  
  7.     int propertyCount, propertyData;  
  8.     int enumeratorCount, enumeratorData;  
  9.     int constructorCount, constructorData; //since revision 2  
  10.     int flags; //since revision 3  
  11.     int signalCount; //since revision 4  
  12.     ...  
  13.     ...   
  14. }  

 接下来是

 

  1. static const char qt_meta_stringdata_myClass[] = {  
  2.     "myClass/0/0signalFunc(double)/0int/0,/0"  
  3.     "signalFunc2(char,int)/0slotFunc(double)/0"  
  4.     "slotFunc2(char)/0"  
  5. };  

 

 

从这个字符串里面,可以看到第一个值为这个类的类名(元对象可以不通过RTTI给出类名的原因就在这里)

在第一个/0后面会给出第一个signal的返回值类型,在这个例子中signalFunc没有返回值,所以没有任何内容,

在第二个/0后面会给出参数名,因为moc读取的是头文件,而我们在头文件中没定义参数名,所以为空

然后就是signal的名字和参数列表类型,这里需要注意的是,即使头文件给出了参数名,在这里也会被忽略掉,只提供类型

再下一个/0后面就是下一个函数的描述了,描述的方式跟前面是一样的。

刚刚提到的9, 34, 56, 73这几个数字,在这里是有用的,这几个数字,刚好是这个字符串对应的函数开头的部分。比如9,那我们在这个字符串中数9个字符,即signalFunc(double)这一段内容。

 

然后是源对象的数据定义:

 

  1. const QMetaObject myClass::staticMetaObject = {  
  2.     { &QObject::staticMetaObject, qt_meta_stringdata_myClass,  
  3.       qt_meta_data_myClass, 0 }  
  4. };  
  5. 可以看到源对象的数据定义为:  
  6.     struct { // private data  
  7.         const QMetaObject *superdata;  
  8.         const char *stringdata;  
  9.         const uint *data;  
  10.         const void *extradata;  
  11.     }  

 

 

这个名为staticMetaObject的对象是由Q_OBJECT引入的

第一个数据为父类名字, moc对于多继承的限制可能也在于此。

moc规定多继承的情况下,moc会假设第一个继承的类为QObject, 并且必须要保证在多继承中,只有唯一一个类是继承自QObject的。这样看上去,多余一个QObject继承的,第二个QObject根本没办法识别出来。

第二个数据就是上面的字符串数据

第三个也是上面的uint*数据。

这个源对象非常关键,后面的内容就靠他了。

  1. const QMetaObject &myClass::getStaticMetaObject() { return staticMetaObject; }  
  2. const QMetaObject *myClass::metaObject() const  
  3. {  
  4.     return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;  
  5. }  

 

这2个方法都是由Q_OBJECT引入的。目的是返回这个类的元对象

  1. void *myClass::qt_metacast(const char *_clname)  
  2. {  
  3.     if (!_clname) return 0;  
  4.     if (!strcmp(_clname, qt_meta_stringdata_myClass))  
  5.         return static_cast<void*>(const_cast< myClass*>(this));  
  6.     return QObject::qt_metacast(_clname);  
  7. }  

 

还是由Q_OBJECT引入的

 

当传入的字符串数据是当前这个类的话,就将this指针转换成void指针传给外界: 这个操作相当危险。

如果不是当前类的话,就调用父类的qt_metacast继续查询。

在这里,我的父类是QObject,所以自然就调用QObject::qt_metacase了

 

在看qt_metacall之前,先看下signal的定义。 额。。事实上signal不需要你自己定义,moc已经帮我们完成这点了。

具体内容如下:

 

  1. // SIGNAL 0  
  2. void myClass::signalFunc(double _t1)  
  3. {  
  4.     void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };  
  5.     QMetaObject::activate(this, &staticMetaObject, 0, _a);  
  6. }  

 我们看到他将所有的参数都转型成void*指针保存到 void *a的数组中,然后调用了

QMetaObject::activate(this, &staticMetaObject, 0, _a);

看到传入的参数为this, 源对象和参数

这个函数实际上就是触发消息的函数,在这里不过多关注他,有机会再写

 

最终,int myClass::qt_metacall(QMetaObject::Call _c, int _id, void **_a)

会被调用,用来处理对应的signal的消息

代码如下

 

  1. int myClass::qt_metacall(QMetaObject::Call _c, int _id, void **_a)  
  2. {  
  3.     _id = QObject::qt_metacall(_c, _id, _a);  
  4.     if (_id < 0)  
  5.         return _id;  
  6.     if (_c == QMetaObject::InvokeMetaMethod) {  
  7.         switch (_id) {  
  8.         case 0: signalFunc((*reinterpret_castdouble(*)>(_a[1]))); break;  
  9.         case 1: { int _r = signalFunc2((*reinterpret_castchar(*)>(_a[1])),(*reinterpret_castint(*)>(_a[2])));  
  10.             if (_a[0]) *reinterpret_castint*>(_a[0]) = _r; }  break;  
  11.         case 2: slotFunc((*reinterpret_castdouble(*)>(_a[1]))); break;  
  12.         case 3: { int _r = slotFunc2((*reinterpret_castchar(*)>(_a[1])));  
  13.             if (_a[0]) *reinterpret_castint*>(_a[0]) = _r; }  break;  
  14.         default: ;  
  15.         }  
  16.         _id -= 4;  
  17.     }  
  18.     return _id;  
  19. }  

这里可以注意下,有返回值和没有返回值的处理方法~

moc所作的这些工作,都是为了元对象能更好的工作而做的准备

分享到:
评论

相关推荐

    Qt Pro转CMakeLists

    同时,还需要使用`qt5_wrap_cpp()`或`qt5_add_resources()`等函数来处理Qt的 moc(元对象编译)和资源文件。 至于压缩包中提到的"cmake"子文件,可能包含了一些辅助脚本或模板,用于帮助转换过程或简化CMake的配置...

    Qt MOC处理器 UML图

    通过分析 C++ 源代码并生成额外的 C++ 代码,它能够支持 Qt 的信号与槽机制、运行时类型信息等功能。 - **UML 图**:UML(Unified Modeling Language)是一种用于描述软件系统的标准化建模语言。在本案例中,UML 图...

    qtcreator生成工程文件 文件列表工具 v1.4(更新)

    由于qtcreator本身没有添加文件夹的功能,要是逐个添加,碰到文件夹较多的情况下十分不方便,此软件主要是生成工程文件(目录名).pro,修复之前版本存在的一些bug,进一步完善。 其主要内容大致如下: QT += core...

    qtcreator生成工程文件 文件列表工具

    由于qtcreator本身没有添加文件夹的功能,要么去linux下生成目录,要么逐个手动添加,十分受限,此软件主要是生成工程文件lastfilelist.pro 其主要内容大致如下: QT += core gui TARGET = targettest TEMPLATE = ...

    QT实现随机生成验证码

    在QT中实现随机生成验证码是一项常见的任务,通常用于用户登录验证、防止机器人操作等安全场景。验证码的目的是通过要求用户输入随机生成的一串字符或图像中的数字,来确保请求是由人类而非机器发起的。 验证码的...

    CppMocTest.7z

    最简单方便的方式就是继承QObject,并在类开头放置Q_OBJECT 这个宏,在预编译前moc 会自动扫描所有头文件,根据 signals 和 slot 关键字,提取信号与槽的所有及对应的信息索引,并为 signals 生成相对应的函数。...

    CMake 生成Qt工程文件(vs2013 or vs2015)

    接着,使用`qt5_wrap_cpp()`或`qt5_add_resources()`处理Qt的MOC(元对象编译)和RC(资源文件)文件。最后,通过`target_link_libraries()`命令将Qt库链接到你的目标可执行文件上。 **Visual Studio集成** CMake...

    qt 查找文件程序

    这些UI文件可以被QT的MOC(Meta-Object Compiler)处理,生成C++代码供程序使用。 在编码过程中,遵循QT的信号和槽机制是关键。当按钮被点击时,信号`clicked()`会被发出,与之连接的槽函数会被调用,执行实际的...

    Qt的pro文件编写方法

    在 pro 文件中,首先需要指定模块设置,基本设置为 app(生成应用程序默认)、subdirs(生成 makefile 文件编译 subdirs 指定的子文件夹)和 lib(生成库文件)。例如: TEMPLATE = app DESTDIR += ../bin TARGET =...

    QT moc definition of dllimport static data member not allow.pdf

    QT库中的moc(Meta-Object Compiler)是用于处理C++的元对象系统,它能够自动为Qt的信号、槽和动态属性等特性生成必要的代码。然而,在特定情况下,当尝试使用`dllimport`和`static`关键字来定义数据成员时,QT moc...

    QT工程中的文件介绍

    其他像`UI_DIR`、`RCC_DIR`、`MOC_DIR`和`OBJECTS_DIR`分别指定了UI文件、资源文件、MOC生成文件和编译生成对象文件的存放目录。 跨平台是QT的一大特点,`.pro`文件可以包含条件语句,根据不同的操作系统设置特定的...

    Qt命名空间 Qt namespace

    通过分析和运行这个示例,你可以更直观地理解Qt命名空间的实际应用。 总的来说,理解并熟练使用Qt命名空间是进行Qt开发的基础。正确地管理和使用命名空间能够提高代码的可读性和可维护性,同时避免潜在的命名冲突...

    有关qt的pro文件

    Qt框架中的.pro文件是Qt构建系统的核心组成部分,用于定义项目的配置和编译规则。这篇文档将深入探讨.pro文件的不同属性及其在Qt项目开发中的作用。 首先,.pro文件是一个纯文本文件,通常使用QMake工具解析,它...

    C++解析头文件-Qt自动生成信号声明

    本文将深入探讨如何使用Qt来解析头文件并自动生成信号声明,以提高代码的可维护性和开发效率。 首先,让我们了解什么是Qt的信号和槽机制。在Qt中,信号和槽是C++类的一种扩展,它们用于对象间的通信。当一个对象的...

    qt2/bin文件目录

    QT2/bin文件目录是Qt开发框架的一个组成部分,主要用于存放可执行文件和其他运行时必要的二进制文件。在软件开发过程中,尤其是使用Qt进行图形用户界面(GUI)编程时,这个目录下的内容至关重要。当我们尝试编译或...

    通过QT QNetworkAccessManager类实现HTTP下载文件的小工具

    `GeneratedFiles`目录通常存放由Qt的元对象编译器(MOC)自动生成的头文件,用于处理Qt的信号和槽机制。 通过这个小例子,初学者不仅可以了解到如何使用QNetworkAccessManager进行HTTP通信,还能掌握Qt的异步编程...

    qt使用的vc规则文件

    3. 将moc生成的C++源文件添加到项目的编译任务中。 4. 可能还包括处理其他Qt特有的构建步骤,如UI文件的uic编译和资源文件的rcc编译。 文件"qt_link.h"和"qt_inc.h"可能是包含Qt库相关头文件的集合,用于确保VC项目...

    CMakeLists.txt使用QT的正确写法

    ### CMakeLists.txt 使用 QT 的正确写法 在软件开发领域,特别是在跨平台应用程序...通过遵循上述指南,开发者可以轻松地集成 Qt5 库到自己的项目中,并利用 CMake 自动生成构建文件的优势,提高开发效率和构建质量。

    Qt将Sqlite中的数据导出为Excel

    4. **创建Excel文件**:在Qt中,我们可以使用`QAxWidget`或`QAxObject`来封装ActiveX控件,调用Microsoft Office的相关API来创建Excel文件。这需要你的目标机器上安装了Microsoft Office,并且用户权限允许运行...

Global site tag (gtag.js) - Google Analytics