qt元对象系统之 Q_OBJECT宏
宏展开是这样
#define Q_OBJECT \ public: \ QT_WARNING_PUSH \ Q_OBJECT_NO_OVERRIDE_WARNING \ static const QMetaObject staticMetaObject; \ virtual const QMetaObject *metaObject() const; \ virtual void *qt_metacast(const char *); \ virtual int qt_metacall(QMetaObject::Call, int, void **); \ QT_TR_FUNCTIONS \ private: \ Q_OBJECT_NO_ATTRIBUTES_WARNING \ Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \ QT_WARNING_POP \ struct QPrivateSignal {}; \ QT_ANNOTATE_CLASS(qt_qobject, "")
然后通过moc工具生成以下变量和函数的定义
静态对象 staticMetaObject
静态方法 qt_static_metacall
成员虚函数 metaObject, qt_meatacast, qt_metacall
例子
class Hello : public QObject { Q_OBJECT };
moc生成的内容
QT_BEGIN_MOC_NAMESPACE QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED struct qt_meta_stringdata_Hello_t { QByteArrayData data[1]; char stringdata0[6]; }; #define QT_MOC_LITERAL(idx, ofs, len) \ Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ qptrdiff(offsetof(qt_meta_stringdata_Hello_t, stringdata0) + ofs \ - idx * sizeof(QByteArrayData)) \ ) static const qt_meta_stringdata_Hello_t qt_meta_stringdata_Hello = { { QT_MOC_LITERAL(0, 0, 5) // "Hello" }, "Hello" }; #undef QT_MOC_LITERAL static const uint qt_meta_data_Hello[] = { // content: 7, // revision 0, // classname 0, 0, // classinfo 0, 0, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors 0, // flags 0, // signalCount 0 // eod }; void Hello::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) { Q_UNUSED(_o); Q_UNUSED(_id); Q_UNUSED(_c); Q_UNUSED(_a); } const QMetaObject Hello::staticMetaObject = { { &QObject::staticMetaObject, qt_meta_stringdata_Hello.data, qt_meta_data_Hello, qt_static_metacall, nullptr, nullptr} }; const QMetaObject *Hello::metaObject() const { return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; } void *Hello::qt_metacast(const char *_clname) { if (!_clname) return nullptr; if (!strcmp(_clname, qt_meta_stringdata_Hello.stringdata0)) return static_cast<void*>(this); return QObject::qt_metacast(_clname); } int Hello::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QObject::qt_metacall(_c, _id, _a); return _id; } QT_WARNING_POP QT_END_MOC_NAMESPACE
QT_MOC_LITERAL用来初始化QByteArrayData结构体,
struct Q_CORE_EXPORT QArrayData { QtPrivate::RefCount ref; int size; uint alloc : 31; uint capacityReserved : 1; qptrdiff offset; // in bytes from beginning of header void *data() { Q_ASSERT(size == 0 || offset < 0 || size_t(offset) >= sizeof(QArrayData)); return reinterpret_cast<char *>(this) + offset; } .... };
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, offset)展开后是{ Q_REFCOUNT_INITIALIZE_STATIC, len, 0, 0, offset }
可以看到 QT_MOC_LITERAL(0, 0, 5) // "Hello"
代表Hello字符串长度5, 最终计算出的offset为字符串地址和用来定位Hello字符串地址所对应的QByteArrayData地址的偏移
注意: 这里只有一个Hello字符串,如果有n个字符串, QByteArrayData data[1]; 就会变成QByteArrayData data[n];
假如Hello字符串所对应的QByteArrayData为data[3], 那么 offset 就是 Hello地址与&data[3]的偏移
此后可以用该对应的QByteArrayData的data()方法取得Hello字符串
qt_meta_data_Hello的头部为这个结构体
struct QMetaObjectPrivate { // revision 7 is Qt 5.0 everything lower is not supported enum { OutputRevision = 7 }; // Used by moc, qmetaobjectbuilder and qdbus int revision; int className; int classInfoCount, classInfoData; int methodCount, methodData; int propertyCount, propertyData; int enumeratorCount, enumeratorData; int constructorCount, constructorData; int flags; int signalCount; .... }
0, 0, // methods如果定义了信号函数或者槽函数, 第二个0就会变成14, 而第一个0则变为信槽总数
注意: 信号函数也是由moc工具自动生成的,而0, // signalCount 中的0则变为信号函数总数
信号函数通常如下
// SIGNAL 0 void Hello::tellName(QString _t1) { void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) }; QMetaObject::activate(this, &staticMetaObject, 0, _a); }
第三个参数是信号在本类中的本地信号索引, 最终会展开为此函数,
void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
其中signalOffset为计算出来的全部父类信号总数, 然后信号的绝对索引为 int signal_index = signalOffset + local_signal_index;
actiate函数的调用,导致所有连接上的槽函数被调用