Qt源码版本
Qt 5.12.0
moc文件
Qt在编译之前会分析源文件,当发现包含了Q_OBJECT宏,则会生成另外一个标准的C++源文件(包含Q_OBJECT宏实现的代码,文件名为moc_+原文件名),该文件同样进入编译系统,最终被链接到二进制代码中去。此时,Qt将自己增加的扩展转换成了标准的C++文件,moc全称是Meta-Object Compiler,也就是“原对象编译器”。
Q_OBJECT的宏定义
位置:qobjectdefs.h
1 /* qmake ignore Q_OBJECT */ 2 #define Q_OBJECT \ 3 public: \ 4 QT_WARNING_PUSH \ 5 Q_OBJECT_NO_OVERRIDE_WARNING \ 6 static const QMetaObject staticMetaObject; \ 7 virtual const QMetaObject *metaObject() const; \ 8 virtual void *qt_metacast(const char *); \ 9 virtual int qt_metacall(QMetaObject::Call, int, void **); \ 10 QT_TR_FUNCTIONS \ 11 private: \ 12 Q_OBJECT_NO_ATTRIBUTES_WARNING \ 13 Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \ 14 QT_WARNING_POP \ 15 struct QPrivateSignal {}; \ 16 QT_ANNOTATE_CLASS(qt_qobject, "")
Moc文件分析
测试代码
1 #include <QObject> 2 class CTestMoc : public QObject 3 { 4 Q_OBJECT 5 public: 6 CTestMoc(){} 7 ~CTestMoc(){} 8 signals: 9 void Test1(); 10 void Test2(int iTemp); 11 private slots: 12 void OnTest1(); 13 void OnTest2(int iTemp); 14 };
Moc代码
测试代码编译之后,生成moc_ctestmoc.cpp文件,包含几个重要的数据结构。
第一个结构是
1 struct qt_meta_stringdata_CTestMoc_t { 2 QByteArrayData data[7]; 3 char stringdata0[44]; 4 };
data字段是一个由数组组成的数组,数组大小取决于信号/槽个数。这个数组在调用QObject::connect时用来匹配信号名或槽名。
stringdata存放的是字符资源,存放全部的信号名、槽名、类名。
1 static const qt_meta_stringdata_CTestMoc_t qt_meta_stringdata_CTestMoc = { 2 { 3 QT_MOC_LITERAL(0, 0, 8), // "CTestMoc" 4 QT_MOC_LITERAL(1, 9, 5), // "Test1" 5 QT_MOC_LITERAL(2, 15, 0), // "" 6 QT_MOC_LITERAL(3, 16, 5), // "Test2" 7 QT_MOC_LITERAL(4, 22, 5), // "iTemp" 8 QT_MOC_LITERAL(5, 28, 7), // "OnTest1" 9 QT_MOC_LITERAL(6, 36, 7) // "OnTest2" 10 11 }, 12 "CTestMoc\0Test1\0\0Test2\0iTemp\0OnTest1\0" 13 "OnTest2" 14 };
qt_meta_stringdata_CTestMoc_t是一个qt_meta_stringdata_CTestMoc的实例
QT_MOC_LITERAL(0, 0, 8),这个宏生成一个byte数组,第一参数是索引,可以看到索引是由 0-6共7个组成,对应的是data字段的长度7;第二个参数是在stringdata字段中的开始位置;第三个参数是长度。QT_MOC_LITERAL(0, 0, 8) 索引是0, 开始位置是0,长度是8,对应的字符是"CTestMoc",后面的以此类推。
结论
- Qt的信号/槽的调用不是通过指针方式调用的,而是通过索引方式来调用的。
- 信号也是一个函数。