原文地址:http://blog.csdn.net/ilvu999/article/details/8049908
使用 meta object system
- 继承自 QOject
- 类定义中添加 Q_OBJECT 宏
- 使用 moc 程序对包含该宏的文件进行处理
采用 qmake 进行处理时,如果头文件xxx.h内包含 Q_OBJECT 宏,将生成 moc_xxx.cpp 文件。如果xxx.cpp文件内包含宏,将生成 xxx.moc 文件(这时,我们需要在xxx.cpp文件内添加 #include"xxx.moc")
Q_OBJECT宏
包括两个方面,
- 该宏在C++中的展开,有编译预处理器完成
- moc 程序对该宏的处理
宏定义
1 #define Q_OBJECT 2 public: 3 Q_OBJECT_CHECK 4 static const QMetaObject staticMetaObject; 5 Q_OBJECT_GETSTATICMETAOBJECT 6 virtual const QMetaObject *metaObject() const; 7 virtual void *qt_metacast(const char *); 8 QT_TR_FUNCTIONS 9 virtual int qt_metacall(QMetaObject::Call, int, void **); 10 private: 11 Q_DECL_HIDDEN static const QMetaObjectExtraData staticMetaObjectExtraData; 12 Q_DECL_HIDDEN static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
而宏 QT_TR_FUNCTIONS 将展开为我们使程序国际化经常使用的 tr 与 trUtf8函数
1 # define QT_TR_FUNCTIONS 2 static inline QString tr(const char *s, const char *c = 0) 3 { return staticMetaObject.tr(s, c); } 4 static inline QString trUtf8(const char *s, const char *c = 0) 5 { return staticMetaObject.trUtf8(s, c); } 6 static inline QString tr(const char *s, const char *c, int n) 7 { return staticMetaObject.tr(s, c, n); } 8 static inline QString trUtf8(const char *s, const char *c, int n) 9 { return staticMetaObject.trUtf8(s, c, n); }
moc 处理
Q_OBJECT 为我们添加了这么多成员函数,而这些函数我们有没有自己去实现,那么其定义在哪儿呢? 这就是 moc 为我们做的,自动生成这些成员函数的定义,放于生成的 xxx.moc 或 moc_xxx.cpp 文件内
注意:两个文件的区别(如果你用cmake或其他工具的话,这点可能很重要)
- 生成的 moc_xxx.cpp 中会自动包含 xxx.h 头文件,所以它可以被独立编译成目标文件(.o 或 .obj)
- 生成的 xxx.moc 是不会包含 xxx.cpp 的(要是包含就出问题了,能发现吧?),因此 xxx.moc 中没有类定义,它无法被独立编译,只能被 include 到 xxx.cpp 中。
QMetaObject
既然 Q_OBJECT 展开成与 QMetaObject 有关的成员函数,看一下QMetaObject 都提供哪些常用功能
- className() 返回类的名字
- superClass() 返回父类的 QMetaObject 对象
- method()与methodCount() 提供meta函数信息(包括signals, slots 与 invokable函数)
- enumerator()与 enumeratorCount() 提供enum类型信息
- propertyCount()与 property() 提供属性信息
- constructor()与 constructorCount() 提供 meta-constructors 信息
既然meta object能为我们的类提供这么多信息,那么这些信息存放哪儿了(大家肯定都能猜到秘密在moc生成的文件内,但为清楚起见,我们看一下QMetaObject的定义)。
这是用 struct 定义的一个类,我们略过其它,只看其数据成员
1 struct Q_CORE_EXPORT QMetaObject 2 { 3 const char *className() const; 4 const QMetaObject *superClass() const; 5 6 QObject *cast(QObject *obj) const; 7 const QObject *cast(const QObject *obj) const; 8 9 #ifndef QT_NO_TRANSLATION 10 // ### Qt 4: Merge overloads 11 QString tr(const char *s, const char *c) const; 12 QString trUtf8(const char *s, const char *c) const; 13 QString tr(const char *s, const char *c, int n) const; 14 QString trUtf8(const char *s, const char *c, int n) const; 15 #endif // QT_NO_TRANSLATION 16 17 int methodOffset() const; 18 int enumeratorOffset() const; 19 int propertyOffset() const; 20 int classInfoOffset() const; 21 22 int constructorCount() const; 23 int methodCount() const; 24 int enumeratorCount() const; 25 int propertyCount() const; 26 int classInfoCount() const; 27 28 int indexOfConstructor(const char *constructor) const; 29 int indexOfMethod(const char *method) const; 30 int indexOfSignal(const char *signal) const; 31 int indexOfSlot(const char *slot) const; 32 int indexOfEnumerator(const char *name) const; 33 int indexOfProperty(const char *name) const; 34 int indexOfClassInfo(const char *name) const; 35 36 QMetaMethod constructor(int index) const; 37 QMetaMethod method(int index) const; 38 QMetaEnum enumerator(int index) const; 39 QMetaProperty property(int index) const; 40 QMetaClassInfo classInfo(int index) const; 41 QMetaProperty userProperty() const; 42 43 static bool checkConnectArgs(const char *signal, const char *method); 44 static QByteArray normalizedSignature(const char *method); 45 static QByteArray normalizedType(const char *type); 46 47 // internal index-based connect 48 static bool connect(const QObject *sender, int signal_index, 49 const QObject *receiver, int method_index, 50 int type = 0, int *types = 0); 51 // internal index-based disconnect 52 static bool disconnect(const QObject *sender, int signal_index, 53 const QObject *receiver, int method_index); 54 static bool disconnectOne(const QObject *sender, int signal_index, 55 const QObject *receiver, int method_index); 56 // internal slot-name based connect 57 static void connectSlotsByName(QObject *o); 58 59 // internal index-based signal activation 60 static void activate(QObject *sender, int signal_index, void **argv); //obsolete 61 static void activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv); //obsolete 62 static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv); 63 static void activate(QObject *sender, const QMetaObject *, int from_local_signal_index, int to_local_signal_index, void **argv); //obsolete 64 65 // internal guarded pointers 66 static void addGuard(QObject **ptr); 67 static void removeGuard(QObject **ptr); 68 static void changeGuard(QObject **ptr, QObject *o); 69 70 static bool invokeMethod(QObject *obj, const char *member, 71 Qt::ConnectionType, 72 QGenericReturnArgument ret, 73 QGenericArgument val0 = QGenericArgument(0), 74 QGenericArgument val1 = QGenericArgument(), 75 QGenericArgument val2 = QGenericArgument(), 76 QGenericArgument val3 = QGenericArgument(), 77 QGenericArgument val4 = QGenericArgument(), 78 QGenericArgument val5 = QGenericArgument(), 79 QGenericArgument val6 = QGenericArgument(), 80 QGenericArgument val7 = QGenericArgument(), 81 QGenericArgument val8 = QGenericArgument(), 82 QGenericArgument val9 = QGenericArgument()); 83 84 static inline bool invokeMethod(QObject *obj, const char *member, 85 QGenericReturnArgument ret, 86 QGenericArgument val0 = QGenericArgument(0), 87 QGenericArgument val1 = QGenericArgument(), 88 QGenericArgument val2 = QGenericArgument(), 89 QGenericArgument val3 = QGenericArgument(), 90 QGenericArgument val4 = QGenericArgument(), 91 QGenericArgument val5 = QGenericArgument(), 92 QGenericArgument val6 = QGenericArgument(), 93 QGenericArgument val7 = QGenericArgument(), 94 QGenericArgument val8 = QGenericArgument(), 95 QGenericArgument val9 = QGenericArgument()) 96 { 97 return invokeMethod(obj, member, Qt::AutoConnection, ret, val0, val1, val2, val3, 98 val4, val5, val6, val7, val8, val9); 99 } 100 101 static inline bool invokeMethod(QObject *obj, const char *member, 102 Qt::ConnectionType type, 103 QGenericArgument val0 = QGenericArgument(0), 104 QGenericArgument val1 = QGenericArgument(), 105 QGenericArgument val2 = QGenericArgument(), 106 QGenericArgument val3 = QGenericArgument(), 107 QGenericArgument val4 = QGenericArgument(), 108 QGenericArgument val5 = QGenericArgument(), 109 QGenericArgument val6 = QGenericArgument(), 110 QGenericArgument val7 = QGenericArgument(), 111 QGenericArgument val8 = QGenericArgument(), 112 QGenericArgument val9 = QGenericArgument()) 113 { 114 return invokeMethod(obj, member, type, QGenericReturnArgument(), val0, val1, val2, 115 val3, val4, val5, val6, val7, val8, val9); 116 } 117 118 static inline bool invokeMethod(QObject *obj, const char *member, 119 QGenericArgument val0 = QGenericArgument(0), 120 QGenericArgument val1 = QGenericArgument(), 121 QGenericArgument val2 = QGenericArgument(), 122 QGenericArgument val3 = QGenericArgument(), 123 QGenericArgument val4 = QGenericArgument(), 124 QGenericArgument val5 = QGenericArgument(), 125 QGenericArgument val6 = QGenericArgument(), 126 QGenericArgument val7 = QGenericArgument(), 127 QGenericArgument val8 = QGenericArgument(), 128 QGenericArgument val9 = QGenericArgument()) 129 { 130 return invokeMethod(obj, member, Qt::AutoConnection, QGenericReturnArgument(), val0, 131 val1, val2, val3, val4, val5, val6, val7, val8, val9); 132 } 133 134 QObject *newInstance(QGenericArgument val0 = QGenericArgument(0), 135 QGenericArgument val1 = QGenericArgument(), 136 QGenericArgument val2 = QGenericArgument(), 137 QGenericArgument val3 = QGenericArgument(), 138 QGenericArgument val4 = QGenericArgument(), 139 QGenericArgument val5 = QGenericArgument(), 140 QGenericArgument val6 = QGenericArgument(), 141 QGenericArgument val7 = QGenericArgument(), 142 QGenericArgument val8 = QGenericArgument(), 143 QGenericArgument val9 = QGenericArgument()) const; 144 145 enum Call { 146 InvokeMetaMethod, 147 ReadProperty, 148 WriteProperty, 149 ResetProperty, 150 QueryPropertyDesignable, 151 QueryPropertyScriptable, 152 QueryPropertyStored, 153 QueryPropertyEditable, 154 QueryPropertyUser, 155 CreateInstance 156 }; 157 158 int static_metacall(Call, int, void **) const; 159 static int metacall(QObject *, Call, int, void **); 160 161 #ifdef QT3_SUPPORT 162 QT3_SUPPORT const char *superClassName() const; 163 #endif 164 165 struct { // private data 166 const QMetaObject *superdata; 167 const char *stringdata; 168 const uint *data; 169 const void *extradata; 170 } d; 171 };
其中呢,
- uperdata,指向父类的MetaObject,容易理解
- extradata 似乎目前未启用,不用理解
- 剩下两个是什么呢? 如你所想,就在 moc 生成的文件内
moc生成的文件
随便找个 moc 文件出来看看
1 static const uint qt_meta_data_HPixmapScene[] = {...}; 2 static const char qt_meta_stringdata_HPixmapScene[] = {...}; 3 const QMetaObject HPixmapScene::staticMetaObject = { 4 { &QGraphicsScene::staticMetaObject, qt_meta_stringdata_HPixmapScene, 5 qt_meta_data_HPixmapScene, 0 } 6 };
这是一个QGraphicsScene的子类。对比前面QMetaObject的数据成员看看,是不是很简单:
- 先分别定义1个 uint 和 char 的数组,
- 用这两个数组首地址和父类的MetaObject的指针初始化 staticMetaObject
- 这个 staticMetaObject 是我们自己的类的静态成员变量
uint数组
接下来我们可以看看 uint 数组,这个数组中存放的是一些索引值,来指导我们从char字符串中提取信息
1 static const uint qt_meta_data_HPixmapScene[] = { 2 3 // content: 4 4, // revision 5 0, // classname 6 0, 0, // classinfo 7 2, 14, // methods 8 0, 0, // properties 9 0, 0, // enums/sets 10 0, 0, // constructors 11 0, // flags 12 0, // signalCount 13 14 // slots: signature, parameters, type, tag, flags 15 18, 14, 13, 13, 0x0a, 16 41, 37, 13, 13, 0x0a, 17 18 0 // eod 19 };
对比QMetaObject用到的数据结构 QMetaObjectPrivate,看看,是不是豁然开朗了:uint 数组中的第一段 就对应这个结构体
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 // revision 5 introduces changes in normalized signatures, no new members 13 // revision 6 added qt_static_metacall as a member of each Q_OBJECT and inside QMetaObject itself 14 15 static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject) 16 { return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); } 17 18 static int indexOfSignalRelative(const QMetaObject **baseObject, 19 const char* name, 20 bool normalizeStringData); 21 static int indexOfSlotRelative(const QMetaObject **m, 22 const char *slot, 23 bool normalizeStringData); 24 static int originalClone(const QMetaObject *obj, int local_method_index); 25 26 #ifndef QT_NO_QOBJECT 27 //defined in qobject.cpp 28 enum DisconnectType { DisconnectAll, DisconnectOne }; 29 static void memberIndexes(const QObject *obj, const QMetaMethod &member, 30 int *signalIndex, int *methodIndex); 31 static bool connect(const QObject *sender, int signal_index, 32 const QObject *receiver, int method_index_relative, 33 const QMetaObject *rmeta = 0, 34 int type = 0, int *types = 0); 35 static bool disconnect(const QObject *sender, int signal_index, 36 const QObject *receiver, int method_index, 37 DisconnectType = DisconnectAll); 38 static inline bool disconnectHelper(QObjectPrivate::Connection *c, 39 const QObject *receiver, int method_index, 40 QMutex *senderMutex, DisconnectType); 41 #endif 42 };