从源码角度分析Qt元对象系统1:https://developer.aliyun.com/article/1597142
2.4 QMetaMethod::typeName 获取函数返回名称
const char *QMetaMethod::typeName() const { if (!mobj) return 0; return QMetaMethodPrivate::get(this)->rawReturnTypeName(); } const char *QMetaMethodPrivate::rawReturnTypeName() const { Q_ASSERT(priv(mobj->d.data)->revision >= 7); // constructors: parameters // 0x80000000 | 2, QMetaType::QObjectStar, 12, // 0x80000000 | 2, // typesDataIndex() 为72,即typeInfo值为 0x80000000 | 2 // IsUnresolvedType值为0x80000000,所以rawStringData指向第二个字符串 uint typeInfo = mobj->d.data[typesDataIndex()]; if (typeInfo & IsUnresolvedType) return rawStringData(mobj, typeInfo & TypeNameIndexMask); else // methods: parameters // QMetaType::Void, // QMetaType::Int, QMetaType::QString, QMetaType::QString, 10, 11, // 即直接通过QMetaType::QString获取相应的名字类型 return QMetaType::typeName(typeInfo); } int QMetaMethodPrivate::typesDataIndex() const { Q_ASSERT(priv(mobj->d.data)->revision >= 7); // constructors: name, argc, parameters, tag, flags // 0, 1, 72, 2, 0x0e /* Public */, // 对应值为72 return mobj->d.data[handle + 2]; }
从上面分析可知,其获取流程大致是先通过QMetaObjectPrivate找到构造函数信息,然后依据其信息获取构造函数参数信息,然后根据参数信息获取名称。
2.5 QMetaMethod::parameterNames
QList<QByteArray> QMetaMethod::parameterNames() const { if (!mobj) return QList<QByteArray>(); return QMetaMethodPrivate::get(this)->parameterNames(); } QList<QByteArray> QMetaMethodPrivate::parameterNames() const { // constructors: name, argc, parameters, tag, flags // 0, 1, 72, 2, 0x0e /* Public */, // 0, 0, 75, 2, 0x2e /* Public | MethodCloned */, // 获取参数个数,即argc int argc = parameterCount(); QList<QByteArray> list; list.reserve(argc); // constructors: parameters // 0x80000000 | 2, QMetaType::QObjectStar, 12, // 0x80000000 | 2, // parametersDataIndex 获取参数信息所在的位置,即指向QMetaType::QObjectStar后的12 // 多个参数依次叠加在一起 int namesIndex = parametersDataIndex() + argc; for (int i = 0; i < argc; ++i) list += stringData(mobj, mobj->d.data[namesIndex + i]); return list; } int QMetaMethodPrivate::parametersDataIndex() const { Q_ASSERT(priv(mobj->d.data)->revision >= 7); return typesDataIndex() + 1; } int QMetaMethodPrivate::typesDataIndex() const { Q_ASSERT(priv(mobj->d.data)->revision >= 7); return mobj->d.data[handle + 2]; }
从上面分析可知,其获取流程大致是先通过QMetaObjectPrivate找到构造函数信息,然后依据其信息获取构造函数参数信息,然后根据参数信息依次获取输入参数信息。
2.6 QMetaMethod::invoke 调用函数
bool QMetaMethod::invoke(QObject *object, Qt::ConnectionType connectionType, QGenericReturnArgument returnValue, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9) const { if (!object || !mobj) return false; Q_ASSERT(mobj->cast(object)); // 检查返回类型是否匹配 if (returnValue.data()) { // 获取返回值类型名 // 与传入的返回值类型名进行比较,不相等则失败返回 const char *retType = typeName(); if (qstrcmp(returnValue.name(), retType) != 0) { // normalize the return value as well QByteArray normalized = QMetaObject::normalizedType(returnValue.name()); if (qstrcmp(normalized.constData(), retType) != 0) { // String comparison failed, try compare the metatype. int t = returnType(); if (t == QMetaType::UnknownType || t != QMetaType::type(normalized)) return false; } } } // 检查参数个数是否匹配,不匹配返回false const char *typeNames[] = { returnValue.name(), val0.name(), val1.name(), val2.name(), val3.name(), val4.name(), val5.name(), val6.name(), val7.name(), val8.name(), val9.name() }; int paramCount; for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) { if (qstrlen(typeNames[paramCount]) <= 0) break; } if (paramCount <= QMetaMethodPrivate::get(this)->parameterCount()) return false; // 检查连接类型,自动连接则依据是否在同一个线程进行修正 QThread *currentThread = QThread::currentThread(); QThread *objectThread = object->thread(); if (connectionType == Qt::AutoConnection) { connectionType = currentThread == objectThread ? Qt::DirectConnection : Qt::QueuedConnection; } #if !QT_CONFIG(thread) if (connectionType == Qt::BlockingQueuedConnection) { connectionType = Qt::DirectConnection; } #endif // 调用函数 void *param[] = { returnValue.data(), val0.data(), val1.data(), val2.data(), val3.data(), val4.data(), val5.data(), val6.data(), val7.data(), val8.data(), val9.data() }; int idx_relative = QMetaMethodPrivate::get(this)->ownMethodIndex(); int idx_offset = mobj->methodOffset(); Q_ASSERT(QMetaObjectPrivate::get(mobj)->revision >= 6); // callFunction为static_metacall,即由moc编译器生成的函数 QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall; if (connectionType == Qt::DirectConnection) { if (callFunction) { callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param); return true; } else { return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, idx_relative + idx_offset, param) < 0; } } else if (connectionType == Qt::QueuedConnection) { if (returnValue.data()) { // 队列调用不支持返回值 qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in " "queued connections"); return false; } int nargs = 1; // include return type void **args = (void **) malloc(paramCount * sizeof(void *)); Q_CHECK_PTR(args); int *types = (int *) malloc(paramCount * sizeof(int)); Q_CHECK_PTR(types); types[0] = 0; // return type args[0] = 0; for (int i = 1; i < paramCount; ++i) { types[i] = QMetaType::type(typeNames[i]); if (types[i] == QMetaType::UnknownType && param[i]) { // Try to register the type and try again before reporting an error. int index = nargs - 1; void *argv[] = { &types[i], &index }; QMetaObject::metacall(object, QMetaObject::RegisterMethodArgumentMetaType, idx_relative + idx_offset, argv); if (types[i] == -1) { qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'", typeNames[i]); for (int x = 1; x < i; ++x) { if (types[x] && args[x]) QMetaType::destroy(types[x], args[x]); } free(types); free(args); return false; } } if (types[i] != QMetaType::UnknownType) { args[i] = QMetaType::create(types[i], param[i]); ++nargs; } } QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction, 0, -1, nargs, types, args)); } else { // blocking queued connection #if QT_CONFIG(thread) if (currentThread == objectThread) { qWarning("QMetaMethod::invoke: Dead lock detected in " "BlockingQueuedConnection: Receiver is %s(%p)", mobj->className(), object); } QSemaphore semaphore; QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction, 0, -1, 0, 0, param, &semaphore)); semaphore.acquire(); #endif // QT_CONFIG(thread) } return true; }
从上面分析可知,其获取流程大致是调用前检查参数与返回值,修正连接模式。如果是
(1)直连则直接通过static_metacall调用
(2)队列模式,则创建参数,然后通过postEvent放入队列,后期调用static_metacall。
QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,0, -1, nargs, types, args));
(3)阻塞队列模式
五、通过QMetaObject::indexOfConstructor
int QMetaObject::indexOfConstructor(const char *constructor) const { Q_ASSERT(priv(d.data)->revision >= 7); QArgumentTypeArray types; QByteArray name = QMetaObjectPrivate::decodeMethodSignature(constructor, types); return QMetaObjectPrivate::indexOfConstructor(this, name, types.size(), types.constData()); } // 给定一个方法的签名(如: "foo(int,double)"), 该函数返回参数类型组(QArgumentTypeArray& types)和方法名 QByteArray QMetaObjectPrivate::decodeMethodSignature( const char *signature, QArgumentTypeArray &types) { Q_ASSERT(signature != 0); const char *lparens = strchr(signature, '('); if (!lparens) return QByteArray(); const char *rparens = strrchr(lparens + 1, ')'); if (!rparens || *(rparens+1)) return QByteArray(); int nameLength = lparens - signature; argumentTypesFromString(lparens + 1, rparens, types); return QByteArray::fromRawData(signature, nameLength); } int QMetaObjectPrivate::indexOfConstructor(const QMetaObject *m, const QByteArray &name, int argc, const QArgumentType *types) { // content: // 8, // revision // 0, // classname // 0, 0, // classinfo // 8, 14, // methods // 1, 76, // properties // 0, 0, // enums/sets // 2, 79, // constructors // 0, // flags // 2, // signalCount // constructorCount为2,constructorData为79 for (int i = priv(m->d.data)->constructorCount-1; i >= 0; --i) { int handle = priv(m->d.data)->constructorData + 5*i; if (methodMatch(m, handle, name, argc, types)) return i; } return -1; } // Returns \c true if the method defined by the given meta-object&handle // matches the given name, argument count and argument types, otherwise // returns \c false. static bool methodMatch(const QMetaObject *m, int handle, const QByteArray &name, int argc, const QArgumentType *types) { Q_ASSERT(priv(m->d.data)->revision >= 7); // constructors: name, argc, parameters, tag, flags // 0, 1, 72, 2, 0x0e /* Public */, // 0, 0, 75, 2, 0x2e /* Public | MethodCloned */, // 比较参数个数 if (int(m->d.data[handle + 1]) != argc) return false; // 比较方法名 if (stringData(m, m->d.data[handle]) != name) return false; // m->d.data[handle + 2]指向下面数据 // constructors: parameters // 0x80000000 | 2, QMetaType::QObjectStar, 12, // 0x80000000 | 2, // 依次比较参数类型,或者参数名 int paramsIndex = m->d.data[handle + 2] + 1; for (int i = 0; i < argc; ++i) { uint typeInfo = m->d.data[paramsIndex + i]; if (types[i].type()) { if (types[i].type() != typeFromTypeInfo(m, typeInfo)) return false; } else { if (types[i].name() != typeNameFromTypeInfo(m, typeInfo)) return false; } } return true; }
从上面分析可知,其流程大致是先把字符串签名,解析成qt内部的参数和方法名,然后依次与保存的方法信息以及参数信息进行比较。都匹配则返回相应的构造函数方法序号。
六、qt_metacall 与 qt_static_metacall
int test::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QObject::qt_metacall(_c, _id, _a); if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { if (_id < 8) qt_static_metacall(this, _c, _id, _a); _id -= 8; } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { if (_id < 8) *reinterpret_cast<int*>(_a[0]) = -1; _id -= 8; } #ifndef QT_NO_PROPERTIES else if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty || _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType) { qt_static_metacall(this, _c, _id, _a); _id -= 1; } else if (_c == QMetaObject::QueryPropertyDesignable) { _id -= 1; } else if (_c == QMetaObject::QueryPropertyScriptable) { _id -= 1; } else if (_c == QMetaObject::QueryPropertyStored) { _id -= 1; } else if (_c == QMetaObject::QueryPropertyEditable) { _id -= 1; } else if (_c == QMetaObject::QueryPropertyUser) { _id -= 1; } #endif // QT_NO_PROPERTIES return _id; } void test::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) { if (_c == QMetaObject::CreateInstance) { switch (_id) { case 0: { test *_r = new test((*reinterpret_cast< QObject*(*)>(_a[1]))); if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break; case 1: { test *_r = new test(); if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break; default: break; } } else if (_c == QMetaObject::InvokeMetaMethod) { auto *_t = static_cast<test *>(_o); Q_UNUSED(_t) switch (_id) { case 0: _t->sgn1(); break; case 1: { int _r = _t->sgn2((*reinterpret_cast< int(*)>(_a[1]))); if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break; case 2: _t->slt1(); break; case 3: { int _r = _t->slt2((*reinterpret_cast< int(*)>(_a[1]))); if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break; case 4: _t->slt3(); break; case 5: { int _r = _t->slt4((*reinterpret_cast< int(*)>(_a[1]))); if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break; case 6: _t->t1(); break; case 7: { int _r = _t->t2((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break; default: ; } } else if (_c == QMetaObject::IndexOfMethod) { int *result = reinterpret_cast<int *>(_a[0]); { using _t = void (test::*)(); if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&test::sgn1)) { *result = 0; return; } } { using _t = int (test::*)(int ); if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&test::sgn2)) { *result = 1; return; } } } #ifndef QT_NO_PROPERTIES else if (_c == QMetaObject::ReadProperty) { auto *_t = static_cast<test *>(_o); Q_UNUSED(_t) void *_v = _a[0]; switch (_id) { case 0: *reinterpret_cast< int*>(_v) = _t->f(); break; default: break; } } else if (_c == QMetaObject::WriteProperty) { auto *_t = static_cast<test *>(_o); Q_UNUSED(_t) void *_v = _a[0]; switch (_id) { case 0: _t->g(*reinterpret_cast< int*>(_v)); break; default: break; } } else if (_c == QMetaObject::ResetProperty) { } #endif // QT_NO_PROPERTIES } // SIGNAL 0 void test::sgn1() { QMetaObject::activate(this, &staticMetaObject, 0, nullptr); } // SIGNAL 1 int test::sgn2(int _t1) { int _t0{}; void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)), const_cast<void*>(reinterpret_cast<const void*>(&_t1)) }; QMetaObject::activate(this, &staticMetaObject, 1, _a); return _t0; }
从上可知,qt_metacall 包含了qt_static_metacall功能。qt_static_metacall主要包含了创建实例、调用方法、属性操作等。因此qt的反射的实现最终实现就是在qt_static_metacall中实现的。
附加属性用法说明:
Qt之自定义属性Q_PROPERTY_wzs的博客-CSDN博客_q_property
Qt之QFlags及相关宏学习小结 - OSCHINA - 中文开源技术交流社区
七、qRegisterMetaType与Q_DECLARE_METATYPE
int id = qRegisterMetaType<MyStruct>(); qRegisterMetaType<MyClass>("MyClass");
此函数可以把类型注册到系统中。qRegisterMetaType函数如下:
template <typename T> inline int qRegisterMetaType() { return qMetaTypeId<T>(); } template <typename T> inline int qMetaTypeId() { return QMetaTypeId2<T>::qt_metatype_id(); } template <typename T> struct QMetaTypeId2 { enum { Defined = QMetaTypeId<T>::Defined, IsBuiltIn=false }; static inline Q_DECL_CONSTEXPR int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); } }; template <typename T> struct QMetaTypeId : public QMetaTypeIdQObject<T> { };
从上面代码可知,qRegisterMetaType经过层层调用,最后调到QMetaTypeIdQObject。QMetaTypeIdQObject也是一个模板,为结构体,其实现如下:
template <typename T, int = QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject : QtPrivate::IsGadgetHelper<T>::IsRealGadget ? QMetaType::IsGadget : QtPrivate::IsPointerToGadgetHelper<T>::IsRealGadget ? QMetaType::PointerToGadget : QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0> struct QMetaTypeIdQObject { enum { Defined = 0 }; };
其根据QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value的值,选择不同的模板:
template <typename T> struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject> { enum { Defined = 1 }; static int qt_metatype_id() { static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); if (const int id = metatype_id.loadAcquire()) return id; const char * const cName = T::staticMetaObject.className(); QByteArray typeName; typeName.reserve(int(strlen(cName)) + 1); typeName.append(cName).append('*'); const int newId = qRegisterNormalizedMetaType<T*>( typeName, reinterpret_cast<T**>(quintptr(-1))); metatype_id.storeRelease(newId); return newId; } }; template <typename T> struct QMetaTypeIdQObject<T, QMetaType::IsGadget> { enum { Defined = std::is_default_constructible<T>::value }; static int qt_metatype_id() { static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); if (const int id = metatype_id.loadAcquire()) return id; const char * const cName = T::staticMetaObject.className(); const int newId = qRegisterNormalizedMetaType<T>( cName, reinterpret_cast<T*>(quintptr(-1))); metatype_id.storeRelease(newId); return newId; } }; template <typename T> struct QMetaTypeIdQObject<T*, QMetaType::PointerToGadget> { enum { Defined = 1 }; static int qt_metatype_id() { static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); if (const int id = metatype_id.loadAcquire()) return id; const char * const cName = T::staticMetaObject.className(); QByteArray typeName; typeName.reserve(int(strlen(cName)) + 1); typeName.append(cName).append('*'); const int newId = qRegisterNormalizedMetaType<T*>( typeName, reinterpret_cast<T**>(quintptr(-1))); metatype_id.storeRelease(newId); return newId; } }; template <typename T> struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration> { enum { Defined = 1 }; static int qt_metatype_id() { static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); if (const int id = metatype_id.loadAcquire()) return id; const char *eName = qt_getEnumName(T()); const char *cName = qt_getEnumMetaObject(T())->className(); QByteArray typeName; typeName.reserve(int(strlen(cName) + 2 + strlen(eName))); typeName.append(cName).append("::").append(eName); const int newId = qRegisterNormalizedMetaType<T>( typeName, reinterpret_cast<T*>(quintptr(-1))); metatype_id.storeRelease(newId); return newId; } };
我们选择:struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>进行分析:
template <typename T> struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject> { enum { Defined = 1 }; static int qt_metatype_id() { static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); if (const int id = metatype_id.loadAcquire()) // 已注册,则直接返回注册的id return id; const char * const cName = T::staticMetaObject.className(); QByteArray typeName; typeName.reserve(int(strlen(cName)) + 1); typeName.append(cName).append('*'); // 注册 const int newId = qRegisterNormalizedMetaType<T*>( typeName, reinterpret_cast<T**>(quintptr(-1))); metatype_id.storeRelease(newId); return newId; } }; template <typename T> int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName #ifndef Q_CLANG_QDOC , T * dummy = 0 , typename QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::DefinedType defined = QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::Defined #endif ) { #ifndef QT_NO_QOBJECT Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()), "qRegisterNormalizedMetaType", "qRegisterNormalizedMetaType was called with a not normalized type name, please call qRegisterMetaType instead."); #endif const int typedefOf = dummy ? -1 : QtPrivate::QMetaTypeIdHelper<T>::qt_metatype_id(); if (typedefOf != -1) return QMetaType::registerNormalizedTypedef(normalizedTypeName, typedefOf); QMetaType::TypeFlags flags(QtPrivate::QMetaTypeTypeFlags<T>::Flags); if (defined) flags |= QMetaType::WasDeclaredAsMetaType; const int id = QMetaType::registerNormalizedType(normalizedTypeName, QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Destruct, QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Construct, int(sizeof(T)), flags, QtPrivate::MetaObjectForType<T>::value()); if (id > 0) { QtPrivate::SequentialContainerConverterHelper<T>::registerConverter(id); QtPrivate::AssociativeContainerConverterHelper<T>::registerConverter(id); QtPrivate::MetaTypePairHelper<T>::registerConverter(id); QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter(id); } return id; } int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, TypedDestructor destructor, TypedConstructor constructor, int size, TypeFlags flags, const QMetaObject *metaObject) { return NS(registerNormalizedType)(normalizedTypeName, nullptr, nullptr, destructor, constructor, size, flags, metaObject); } static int registerNormalizedType(const NS(QByteArray) &normalizedTypeName, QMetaType::Destructor destructor, QMetaType::Constructor constructor, QMetaType::TypedDestructor typedDestructor, QMetaType::TypedConstructor typedConstructor, int size, QMetaType::TypeFlags flags, const QMetaObject *metaObject) { // 自定义类型会注册到这个全局变量中 QVector<QCustomTypeInfo> *ct = customTypes(); if (!ct || normalizedTypeName.isEmpty() || (!destructor && !typedDestructor) || (!constructor && !typedConstructor)) return -1; // 先去全局静态变量中查找(即查找系统自己注册的),没找到则去自定义全局注册变量中查找 int idx = qMetaTypeStaticType(normalizedTypeName.constData(), normalizedTypeName.size()); int previousSize = 0; QMetaType::TypeFlags::Int previousFlags = 0; if (idx == QMetaType::UnknownType) { QWriteLocker locker(customTypesLock()); int posInVector = -1; // 在自定义全局注册变量中查找,没有则创建QCustomTypeInfo注册进customTypes()中 idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), normalizedTypeName.size(), &posInVector); if (idx == QMetaType::UnknownType) { QCustomTypeInfo inf; inf.typeName = normalizedTypeName; #ifndef QT_NO_DATASTREAM inf.loadOp = 0; inf.saveOp = 0; #endif inf.alias = -1; inf.typedConstructor = typedConstructor; inf.typedDestructor = typedDestructor; inf.constructor = constructor; inf.destructor = destructor; inf.size = size; inf.flags = flags; inf.metaObject = metaObject; if (posInVector == -1) { // id为注册序号 + 自定义偏移,即前面为系统默认注册位置,后面才是用户注册的位置 idx = ct->size() + QMetaType::User; ct->append(inf); } else { idx = posInVector + QMetaType::User; ct->data()[posInVector] = inf; } return idx; } if (idx >= QMetaType::User) { previousSize = ct->at(idx - QMetaType::User).size; previousFlags = ct->at(idx - QMetaType::User).flags; // Set new/additional flags in case of old library/app. // Ensures that older code works in conjunction with new Qt releases // requiring the new flags. if (flags != previousFlags) { QCustomTypeInfo &inf = ct->data()[idx - QMetaType::User]; inf.flags |= flags; if (metaObject) inf.metaObject = metaObject; } } } if (idx < QMetaType::User) { previousSize = QMetaType::sizeOf(idx); previousFlags = QMetaType::typeFlags(idx); } if (Q_UNLIKELY(previousSize != size)) { qFatal("QMetaType::registerType: Binary compatibility break " "-- Size mismatch for type '%s' [%i]. Previously registered " "size %i, now registering size %i.", normalizedTypeName.constData(), idx, previousSize, size); } // these flags cannot change in a binary compatible way: const int binaryCompatibilityFlag = QMetaType::PointerToQObject | QMetaType::IsEnumeration | QMetaType::SharedPointerToQObject | QMetaType::WeakPointerToQObject | QMetaType::TrackingPointerToQObject; if (Q_UNLIKELY((previousFlags ^ flags) & binaryCompatibilityFlag)) { const char *msg = "QMetaType::registerType: Binary compatibility break. " "\nType flags for type '%s' [%i] don't match. Previously " "registered TypeFlags(0x%x), now registering TypeFlags(0x%x). "; qFatal(msg, normalizedTypeName.constData(), idx, previousFlags, int(flags)); } return idx; }
注册大致流程为:若metatype_id有值,则说明已经注册,直接返回注册序号。否则先去系统默认全局注册变量中查找,没找到再去用户注册变量中查找,如果没有说明没有注册,则构建QCustomTypeInfo的信息,并把它注册进用户注册变量中,同时返回用户注册顺序为注册Id。
接下来再分析下系统默认全局注册变量types[]和用户注册变量customTypes(),先看 types[],其查找在qMetaTypeStaticType函数中:
static inline int qMetaTypeStaticType(const char *typeName, int length) { int i = 0; while (types[i].typeName && ((length != types[i].typeNameLength) || memcmp(typeName, types[i].typeName, length))) { ++i; } return types[i].type; } static const struct { const char * typeName; int typeNameLength; int type; } types[] = { QT_FOR_EACH_STATIC_TYPE(QT_ADD_STATIC_METATYPE) QT_FOR_EACH_STATIC_ALIAS_TYPE(QT_ADD_STATIC_METATYPE_ALIASES_ITER) QT_FOR_EACH_STATIC_HACKS_TYPE(QT_ADD_STATIC_METATYPE_HACKS_ITER) {0, 0, QMetaType::UnknownType} }; #define QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeId, RealName) \ { #RealName, sizeof(#RealName) - 1, MetaTypeId }, #define QT_ADD_STATIC_METATYPE_ALIASES_ITER(MetaTypeName, MetaTypeId, AliasingName, RealNameStr) \ { RealNameStr, sizeof(RealNameStr) - 1, QMetaType::MetaTypeName }, #define QT_ADD_STATIC_METATYPE_HACKS_ITER(MetaTypeName, TypeId, Name) \ QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeName, Name)
types是一个全局静态结构体数组,包含名称,名称长度以及类型,其通过三个宏,初始化了一系列系统自带的变量,如基本类型(void, bool),基本指针类型,核心类等。
#define QT_FOR_EACH_STATIC_TYPE(F)\ QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\ QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\ QT_FOR_EACH_STATIC_CORE_CLASS(F)\ QT_FOR_EACH_STATIC_CORE_POINTER(F)\ QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\ QT_FOR_EACH_STATIC_GUI_CLASS(F)\ QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\ // 注册基本类型 #define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\ F(Void, 43, void) \ F(Bool, 1, bool) \ F(Int, 2, int) \ F(UInt, 3, uint) \ F(LongLong, 4, qlonglong) \ F(ULongLong, 5, qulonglong) \ F(Double, 6, double) \ F(Long, 32, long) \ F(Short, 33, short) \ F(Char, 34, char) \ F(ULong, 35, ulong) \ F(UShort, 36, ushort) \ F(UChar, 37, uchar) \ F(Float, 38, float) \ F(SChar, 40, signed char) \ F(Nullptr, 51, std::nullptr_t) \ F(QCborSimpleType, 52, QCborSimpleType) \ // 注册基本指针类型 #define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\ F(VoidStar, 31, void*) \ // 注册核心类 #define QT_FOR_EACH_STATIC_CORE_CLASS(F)\ F(QChar, 7, QChar) \ F(QString, 10, QString) \ F(QStringList, 11, QStringList) \ F(QByteArray, 12, QByteArray) \ F(QBitArray, 13, QBitArray) \ F(QDate, 14, QDate) \ F(QTime, 15, QTime) \ F(QDateTime, 16, QDateTime) \ F(QUrl, 17, QUrl) \ F(QLocale, 18, QLocale) \ F(QRect, 19, QRect) \ F(QRectF, 20, QRectF) \ F(QSize, 21, QSize) \ F(QSizeF, 22, QSizeF) \ F(QLine, 23, QLine) \ F(QLineF, 24, QLineF) \ F(QPoint, 25, QPoint) \ F(QPointF, 26, QPointF) \ F(QRegExp, 27, QRegExp) \ F(QEasingCurve, 29, QEasingCurve) \ F(QUuid, 30, QUuid) \ F(QVariant, 41, QVariant) \ F(QRegularExpression, 44, QRegularExpression) \ F(QJsonValue, 45, QJsonValue) \ F(QJsonObject, 46, QJsonObject) \ F(QJsonArray, 47, QJsonArray) \ F(QJsonDocument, 48, QJsonDocument) \ F(QCborValue, 53, QCborValue) \ F(QCborArray, 54, QCborArray) \ F(QCborMap, 55, QCborMap) \ QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F) // 注册核心指针类 #define QT_FOR_EACH_STATIC_CORE_POINTER(F)\ F(QObjectStar, 39, QObject*) #define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\ F(QVariantMap, 8, QVariantMap) \ F(QVariantList, 9, QVariantList) \ F(QVariantHash, 28, QVariantHash) \ F(QByteArrayList, 49, QByteArrayList) \ #define QT_FOR_EACH_STATIC_GUI_CLASS(F)\ F(QFont, 64, QFont) \ F(QPixmap, 65, QPixmap) \ F(QBrush, 66, QBrush) \ F(QColor, 67, QColor) \ F(QPalette, 68, QPalette) \ F(QIcon, 69, QIcon) \ F(QImage, 70, QImage) \ F(QPolygon, 71, QPolygon) \ F(QRegion, 72, QRegion) \ F(QBitmap, 73, QBitmap) \ F(QCursor, 74, QCursor) \ F(QKeySequence, 75, QKeySequence) \ F(QPen, 76, QPen) \ F(QTextLength, 77, QTextLength) \ F(QTextFormat, 78, QTextFormat) \ F(QMatrix, 79, QMatrix) \ F(QTransform, 80, QTransform) \ F(QMatrix4x4, 81, QMatrix4x4) \ F(QVector2D, 82, QVector2D) \ F(QVector3D, 83, QVector3D) \ F(QVector4D, 84, QVector4D) \ F(QQuaternion, 85, QQuaternion) \ F(QPolygonF, 86, QPolygonF) \ #define QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\ F(QSizePolicy, 121, QSizePolicy) \
上述宏扩展开如:
QT_FOR_EACH_STATIC_TYPE(QT_ADD_STATIC_METATYPE) // 扩展QT_FOR_EACH_STATIC_TYPE #define QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeId, RealName) \ { #RealName, sizeof(#RealName) - 1, MetaTypeId }, // QT_FOR_EACH_STATIC_TYPE 部分内容为 F(Void, 43, void) \ F(Bool, 1, bool) \ F(UInt, 3, uint) \ F(ULong, 35, ulong) \ F(UShort, 36, ushort) \ // 扩展后实际内容为: { "void", sizeof("void") - 1, 43}, { "bool", sizeof("bool") - 1, 1}, { "uint", sizeof("uint") - 1, 3}, { "ulong", sizeof("ulong") - 1, 35}, { "ushort", sizeof("ushort") - 1, 36}, // ======================================================================== QT_FOR_EACH_STATIC_ALIAS_TYPE(QT_ADD_STATIC_METATYPE_ALIASES_ITER) #define QT_ADD_STATIC_METATYPE_ALIASES_ITER(MetaTypeName, MetaTypeId, AliasingName, RealNameStr) \ { RealNameStr, sizeof(RealNameStr) - 1, QMetaType::MetaTypeName }, // QT_FOR_EACH_STATIC_ALIAS_TYPE 部分内容为 F(ULong, -1, ulong, "unsigned long") \ F(UInt, -1, uint, "unsigned int") \ F(UShort, -1, ushort, "unsigned short") \ // 扩展后实际内容为: { "unsigned long", sizeof("unsigned long") - 1, 35}, { "unsigned int", sizeof("unsigned int") - 1, 3}, { "unsigned short", sizeof("unsigned short") - 1, 36}, // 备注:QMetaType::UInt 值正为3,由qt系统定义好了
接下来看用户注册变量customTypes():
Q_GLOBAL_STATIC(QVector<QCustomTypeInfo>, customTypes) #define Q_GLOBAL_STATIC(TYPE, NAME) \ Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ()) #define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ namespace { namespace Q_QGS_ ## NAME { \ typedef TYPE Type; \ QBasicAtomicInt guard = Q_BASIC_ATOMIC_INITIALIZER(QtGlobalStatic::Uninitialized); \ Q_GLOBAL_STATIC_INTERNAL(ARGS) \ } } \ static QGlobalStatic<TYPE, \ Q_QGS_ ## NAME::innerFunction, \ Q_QGS_ ## NAME::guard> NAME; #define Q_GLOBAL_STATIC_INTERNAL(ARGS) \ Q_GLOBAL_STATIC_INTERNAL_DECORATION Type *innerFunction() \ { \ struct HolderBase { \ ~HolderBase() Q_DECL_NOTHROW \ { if (guard.load() == QtGlobalStatic::Initialized) \ guard.store(QtGlobalStatic::Destroyed); } \ }; \ static struct Holder : public HolderBase { \ Type value; \ Holder() \ Q_DECL_NOEXCEPT_EXPR(noexcept(Type ARGS)) \ : value ARGS \ { guard.store(QtGlobalStatic::Initialized); } \ } holder; \ return &holder.value; \ } template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard> struct QGlobalStatic { typedef T Type; bool isDestroyed() const { return guard.load() <= QtGlobalStatic::Destroyed; } bool exists() const { return guard.load() == QtGlobalStatic::Initialized; } operator Type *() { if (isDestroyed()) return 0; return innerFunction(); } Type *operator()() { if (isDestroyed()) return 0; return innerFunction(); } Type *operator->() { Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed"); return innerFunction(); } Type &operator*() { Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed"); return *innerFunction(); } }; // 其展开为: namespace { namespace Q_QGS_customTypes { typedef QVector<QCustomTypeInfo> Type; QBasicAtomicInt guard = Q_BASIC_ATOMIC_INITIALIZER(QtGlobalStatic::Uninitialized); QVector<QCustomTypeInfo> *innerFunction() { ... static struct Holder : public HolderBase { QVector<QCustomTypeInfo> value; ... } holder; return &holder.value; } } } static QGlobalStatic<QVector<QCustomTypeInfo>, Q_QGS_customTypes::innerFunction, Q_QGS_customTypes::guard>customTypes
从上可知QVector<QCustomTypeInfo> *ct = customTypes();由于QGlobalStatic中对()进行了重载,所以其相当于调用:
QVector<QCustomTypeInfo> *ct = customTypes(); // 相当于调用QGlobalStatic中operator()重载方法,而innerFunction()在构造时传入, // 其值为Q_QGS_customTypes 中innerFunction函数,其定义了静态的持有变量holder struct QGlobalStatic { QVector<QCustomTypeInfo>*operator()() { if (isDestroyed()) return 0; return innerFunction(); } }; namespace { namespace Q_QGS_customTypes { QVector<QCustomTypeInfo> *innerFunction() { ... static struct Holder : public HolderBase { QVector<QCustomTypeInfo> value; ... } holder; return &holder.value; } } }
小结
class test : public QObject { Q_OBJECT public: explicit test(QObject *parent = nullptr); QString name; } class T1 { public: QString name; }; class T2 { public: QString name; }; Q_DECLARE_METATYPE(T2) //Q_DECLARE_METATYPE(T2*) void main() { int typeId = qRegisterMetaType<test *>(); // qRegisterMetaType<test>(); // 编译不过,QObject及其子类无默认的复制函数 // qRegisterMetaType<test>("test"); // 编译不过,QObject及其子类无默认的复制函数 //int typeId4 = qRegisterMetaType<T2 *>(); // 编译不过,未声明Q_DECLARE_METATYPE(T2*) int typeId5 = qRegisterMetaType<T2>(); int typeId2 = qRegisterMetaType<T1 *>("T1"); int typeId22 = qRegisterMetaType<T1 *>("T1*"); int typeId3 = qRegisterMetaType<T1>("T1"); // 与 typeId2 相同,说明与类型无关,与名字相关 int typeId33 = qRegisterMetaType<T1>("T1 *"); // 与 typeId22 相同,说明与类型无关,与名字相关 }
qRegisterMetaType<T>():
- 可以注册QObject的子类指针(test继承QObject),qRegisterMetaType<test *>();
- 不能注册QObject的子类本身(test继承QObject),qRegisterMetaType<test>()无法完成注册,因为无默认的构造、复制、析构函数。(信号与槽无法传递参数)
- 可以注册由Q_DECLARE_METATYPE声明结构体、类
int qRegisterMetaType(const char *typeName):
- 可以注册有默认的构造、复制、析构函数的结构体或类
- 返回的注册id只与typeName相关
扩展阅读
Q_DECLARE_METATYPE与qRegisterMetaType学习-BinChengfei-ChinaUnix博客
Qt笔记之Q_DECLARE_METATYPE(Type)_地上的苹果-CSDN博客_q_declare_metatype
Qt文档阅读笔记-关于Q_DECLARE_METATYPE原理以及使用_IT1995的博客-CSDN博客_q_declare_metatype
qRegisterMetaType的使用_wadfji的博客-CSDN博客_qregistermetatype
Qt原子操作之QBasicAtomicInt和QBasicAtomicInt_Mario_z的博客-CSDN博客
八、信号与槽
Qt高级——Qt信号槽机制源码解析【附源码】_天山老妖S_51CTO博客
Qt的信号和槽是如何工作的_imxiangzi的专栏-CSDN博客
1、连接函数connect
connect其中一个实现为:
template <typename Func1, typename Func2> static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot, Qt::ConnectionType type = Qt::AutoConnection) { typedef QtPrivate::FunctionPointer<Func1> SignalType; const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value; const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0; typedef typename QtPrivate::FunctorReturnType<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType; const int *types = nullptr; if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(); return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr, new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value, typename SignalType::ReturnType>(std::move(slot)), type, types, &SignalType::Object::staticMetaObject); }
connect是一个模板,其展开并精简后为:
QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection) { ... return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr, new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value, typename SignalType::ReturnType>(std::move(slot)), type, types, &SignalType::Object::staticMetaObject); }
接下来看函数connectImpl:
QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, const int *types, const QMetaObject *senderMetaObject) { if (!signal) { qWarning("QObject::connect: invalid null parameter"); if (slotObj) slotObj->destroyIfLastRef(); return QMetaObject::Connection(); } int signal_index = -1; void *args[] = { &signal_index, signal }; // 通过信号函数找到其在moc中的序号, // senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args) // 最终会调用moc文件中的qt_static_metacall方法里的IndexOfMethod情况 // { // using _t = int (test::*)(QString * ); // if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&test::sgn4)) { // *result = 3; // return; // } // } // { // using _t = int (test::*)(QString , QString , int ); // if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&test::sgn5)) { // *result = 4; // return; // } // } for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) { senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args); if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount) break; } if (!senderMetaObject) { qWarning("QObject::connect: signal not found in %s", sender->metaObject()->className()); slotObj->destroyIfLastRef(); return QMetaObject::Connection(0); } // 把当前类中的信号顺序转换成全局中的信号,其转换方法为依次叠加父类中的信号个数 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject); // 进一步处理信号与槽的连接 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject); } int QMetaObjectPrivate::signalOffset(const QMetaObject *m) { Q_ASSERT(m != 0); int offset = 0; // 依次叠加父类中的信号个数,最后返回总父类们信号总个数 for (m = m->d.superdata; m; m = m->d.superdata) offset += priv(m->d.data)->signalCount; return offset; }
接下来我们看进一步处理信号与槽连接的函数connectImpl,其参数为(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject):
QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index, const QObject *receiver, void **slot, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, const int *types, const QMetaObject *senderMetaObject) { if (!sender || !receiver || !slotObj || !senderMetaObject) { const char *senderString = sender ? sender->metaObject()->className() : senderMetaObject ? senderMetaObject->className() : "Unknown"; const char *receiverString = receiver ? receiver->metaObject()->className() : "Unknown"; qWarning("QObject::connect(%s, %s): invalid null parameter", senderString, receiverString); if (slotObj) slotObj->destroyIfLastRef(); return QMetaObject::Connection(); } // 发送者 QObject *s = const_cast<QObject *>(sender); // 信号接收者,即槽函数所在的对象 QObject *r = const_cast<QObject *>(receiver); QOrderedMutexLocker locker(signalSlotLock(sender), signalSlotLock(receiver)); // 处理唯一连接的情况 if (type & Qt::UniqueConnection && slot) { QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists; if (connectionLists && connectionLists->count() > signal_index) { const QObjectPrivate::Connection *c2 = (*connectionLists)[signal_index].first; while (c2) { if (c2->receiver == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) { slotObj->destroyIfLastRef(); return QMetaObject::Connection(); } c2 = c2->nextConnectionList; } } type = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection); } QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection); c->sender = s; c->signal_index = signal_index; c->receiver = r; c->slotObj = slotObj; c->connectionType = type; c->isSlotObject = true; if (types) { c->argumentTypes.store(types); c->ownArgumentTypes = false; } // 新建一个Connection,并添加到QObjectPrivate::connectionLists中, // connectionLists是一个QVector,以信号顺序为索引 QObjectPrivate::get(s)->addConnection(signal_index, c.data()); QMetaObject::Connection ret(c.take()); locker.unlock(); QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index); Q_ASSERT(method.isValid()); s->connectNotify(method); return ret; } void QObjectPrivate::addConnection(int signal, Connection *c) { Q_ASSERT(c->sender == q_ptr); // connectionLists类型为QObjectConnectionListVector, // 其继承QVector<QObjectPrivate::ConnectionList> // 其以信号顺序为索引,没有则创建,不够则调整数组大小 // struct ConnectionList { // ConnectionList() : first(nullptr), last(nullptr) {} // Connection *first; // Connection *last; // }; if (!connectionLists) connectionLists = new QObjectConnectionListVector(); if (signal >= connectionLists->count()) connectionLists->resize(signal + 1); // ConnectionList中first指向第一个,last指向最后一个,后面添加的都放在末尾 ConnectionList &connectionList = (*connectionLists)[signal]; if (connectionList.last) { connectionList.last->nextConnectionList = c; } else { connectionList.first = c; } connectionList.last = c; // 清除失效的连接 cleanConnectionLists(); // 接收者的senders指向最后一个与其连接的信号的Connection // Connection 的 prev 指向接收者的senders的地址,next指向senders本身, // 而接收者的senders始终指向最后一个与其相连的信号的Connection // 所以当信号连接槽时,若槽上已经有别的信号与其连接,则当前Connection的pre指向槽对象senders的地址, // 其next指向上一个与槽连接的信号Connection , // 并且把上一个与槽连接的信号Connection的pre由指向 // 槽对象senders的地址改成指向其本身 c->prev = &(QObjectPrivate::get(c->receiver)->senders); c->next = *c->prev; *c->prev = c; if (c->next) c->next->prev = &c->next; if (signal < 0) { connectedSignals[0].store(~0); connectedSignals[1].store(~0); } else if (signal < (int)sizeof(connectedSignals) * 8) { connectedSignals[signal >> 5].store(connectedSignals[signal >> 5].load() | (1 << (signal & 0x1f))); } }
2、信号发送
void t5() { int r = emit sgn5("name", "sex", 18); qDebug() << "t5 return " << r; } // SIGNAL 4 int test::sgn5(QString _t1, QString _t2, int _t3) { int _t0{}; void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)), const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)), const_cast<void*>(reinterpret_cast<const void*>(&_t3)) }; QMetaObject::activate(this, &staticMetaObject, 4, _a); return _t0; } void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, void **argv) { // signalOffset找到全局的信号序号 activate(sender, QMetaObjectPrivate::signalOffset(m), local_signal_index, argv); } void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv) { int signal_index = signalOffset + local_signal_index; if (sender->d_func()->blockSig) return; Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index); if (sender->d_func()->isDeclarativeSignalConnected(signal_index) && QAbstractDeclarativeData::signalEmitted) { Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index); QAbstractDeclarativeData::signalEmitted(sender->d_func()->declarativeData, sender, signal_index, argv); } if (!sender->d_func()->isSignalConnected(signal_index, /*checkDeclarative =*/ false) && !qt_signal_spy_callback_set.signal_begin_callback && !qt_signal_spy_callback_set.signal_end_callback) { // The possible declarative connection is done, and nothing else is connected, so: return; } void *empty_argv[] = { 0 }; if (qt_signal_spy_callback_set.signal_begin_callback != 0) { qt_signal_spy_callback_set.signal_begin_callback(sender, signal_index, argv ? argv : empty_argv); } { QMutexLocker locker(signalSlotLock(sender)); struct ConnectionListsRef { QObjectConnectionListVector *connectionLists; ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists) { if (connectionLists) ++connectionLists->inUse; } ~ConnectionListsRef() { if (!connectionLists) return; --connectionLists->inUse; Q_ASSERT(connectionLists->inUse >= 0); if (connectionLists->orphaned) { if (!connectionLists->inUse) delete connectionLists; } } QObjectConnectionListVector *operator->() const { return connectionLists; } }; ConnectionListsRef connectionLists = sender->d_func()->connectionLists; if (!connectionLists.connectionLists) { locker.unlock(); if (qt_signal_spy_callback_set.signal_end_callback != 0) qt_signal_spy_callback_set.signal_end_callback(sender, signal_index); return; } const QObjectPrivate::ConnectionList *list; if (signal_index < connectionLists->count()) list = &connectionLists->at(signal_index); else list = &connectionLists->allsignals; Qt::HANDLE currentThreadId = QThread::currentThreadId(); do { QObjectPrivate::Connection *c = list->first; if (!c) continue; // We need to check against last here to ensure that signals added // during the signal emission are not emitted in this emission. QObjectPrivate::Connection *last = list->last; // 依次调用与信号连接的槽函数 do { if (!c->receiver) continue; QObject * const receiver = c->receiver; const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId.load(); // determine if this connection should be sent immediately or // put into the event queue // 判断connection 是否立即执行还是放入队列中 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread) || (c->connectionType == Qt::QueuedConnection)) { // 放入队列中 queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker); continue; #if QT_CONFIG(thread) } else if (c->connectionType == Qt::BlockingQueuedConnection) { // 放入阻塞队列中 if (receiverInSameThread) { qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: " "Sender is %s(%p), receiver is %s(%p)", sender->metaObject()->className(), sender, receiver->metaObject()->className(), receiver); } QSemaphore semaphore; QMetaCallEvent *ev = c->isSlotObject ? new QMetaCallEvent(c->slotObj, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore) : new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore); QCoreApplication::postEvent(receiver, ev); locker.unlock(); semaphore.acquire(); locker.relock(); continue; #endif } QConnectionSenderSwitcher sw; if (receiverInSameThread) { sw.switchSender(receiver, sender, signal_index); } // 连接时采用函数指针形式进入此入口,如:connect(tObj, &test::sgn3, this, &MainWindow::slt3); if (c->isSlotObject) { c->slotObj->ref(); QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj); locker.unlock(); { Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, obj.data()); obj->call(receiver, argv ? argv : empty_argv); } // Make sure the slot object gets destroyed before the mutex is locked again, as the // destructor of the slot object might also lock a mutex from the signalSlotLock() mutex pool, // and that would deadlock if the pool happens to return the same mutex. obj.reset(); locker.relock(); } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { // 连接时采用函数参数字符串的形式,则进入此分支,如:connect(tObj, SIGNAL(sgn4(QString *)), this, SLOT(slt4(QString*))); //we compare the vtable to make sure we are not in the destructor of the object. const int methodIndex = c->method(); const int method_relative = c->method_relative; const auto callFunction = c->callFunction; locker.unlock(); if (qt_signal_spy_callback_set.slot_begin_callback != 0) qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv); { Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex); callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv); } if (qt_signal_spy_callback_set.slot_end_callback != 0) qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex); locker.relock(); } else { const int method = c->method_relative + c->method_offset; locker.unlock(); if (qt_signal_spy_callback_set.slot_begin_callback != 0) { qt_signal_spy_callback_set.slot_begin_callback(receiver, method, argv ? argv : empty_argv); } { Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method); metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); } if (qt_signal_spy_callback_set.slot_end_callback != 0) qt_signal_spy_callback_set.slot_end_callback(receiver, method); locker.relock(); } if (connectionLists->orphaned) break; } while (c != last && (c = c->nextConnectionList) != 0); if (connectionLists->orphaned) break; } while (list != &connectionLists->allsignals && //start over for all signals; ((list = &connectionLists->allsignals), true)); } if (qt_signal_spy_callback_set.signal_end_callback != 0) qt_signal_spy_callback_set.signal_end_callback(sender, signal_index); }
2.1 直连Qt::DirectConnection
c->isSlotObject:obj->call(receiver, argv ? argv : empty_argv); 因为直接调用,argv指向的参数都存在,所以不能拷贝参数。连接采用指针时,isSlotObject为真,如:connect(tObj, &test::sgn3, this, &MainWindow::slt3),否则以字符串形式连接为false,如:connect(tObj, SIGNAL(sgn4(QString *)), this, SLOT(slt4(QString*)));,此时其调用为
else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { //we compare the vtable to make sure we are not in the destructor of the object. const int methodIndex = c->method(); const int method_relative = c->method_relative; const auto callFunction = c->callFunction; locker.unlock(); if (qt_signal_spy_callback_set.slot_begin_callback != 0) qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv); { Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex); callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv); } if (qt_signal_spy_callback_set.slot_end_callback != 0) qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex); locker.relock(); }
callFunction指向:槽函数所在对象的MainWindow::qt_static_metacall方法
2.2 队列Qt::QueuedConnection
static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv, QMutexLocker &locker) { // 获取参数类型,这里参数为(QString, QString, int),argumentTypes 对应的值为10,10,2 // 为QMetaType::Type中的值,QMetaType::QString为10,QMetaType::Int为2 const int *argumentTypes = c->argumentTypes.load(); if (!argumentTypes) { QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal); argumentTypes = queuedConnectionTypes(m.parameterTypes()); if (!argumentTypes) // cannot queue arguments argumentTypes = &DIRECT_CONNECTION_ONLY; if (!c->argumentTypes.testAndSetOrdered(0, argumentTypes)) { if (argumentTypes != &DIRECT_CONNECTION_ONLY) delete [] argumentTypes; argumentTypes = c->argumentTypes.load(); } } if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate return; int nargs = 1; // include return type while (argumentTypes[nargs-1]) ++nargs; // 动态创建返回值和参数的类型空间 int *types = (int *) malloc(nargs*sizeof(int)); Q_CHECK_PTR(types); // 动态创建返回值和参数的值空间 void **args = (void **) malloc(nargs*sizeof(void *)); Q_CHECK_PTR(args); types[0] = 0; // return type args[0] = 0; // return value if (nargs > 1) { // 填入参数类型, QMetaType::Type for (int n = 1; n < nargs; ++n) types[n] = argumentTypes[n-1]; locker.unlock(); // 填入参数的值, 即动态复制参数,args中保存了动态复制的参数地址 // 如QString参数, 先分配存储空间,然后复制QString,最后args[0]指向这个空间 for (int n = 1; n < nargs; ++n) args[n] = QMetaType::create(types[n], argv[n]); locker.relock(); if (!c->receiver) { locker.unlock(); // we have been disconnected while the mutex was unlocked for (int n = 1; n < nargs; ++n) QMetaType::destroy(types[n], args[n]); free(types); free(args); locker.relock(); return; } } QMetaCallEvent *ev = c->isSlotObject ? new QMetaCallEvent(c->slotObj, sender, signal, nargs, types, args) : new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs, types, args); // 发送事件到队列中 QCoreApplication::postEvent(c->receiver, ev); }
构建好QMetaCallEvent事件后,通过postEvent进行发送,后面队列将处理这个消息,其调用堆栈为:
bool QObject::event(QEvent *e) { ... case QEvent::MetaCall: { QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e); QConnectionSenderSwitcher sw(this, const_cast<QObject*>(mce->sender()), mce->signalId()); mce->placeMetaCall(this); break; } ... } void QMetaCallEvent::placeMetaCall(QObject *object) { if (slotObj_) { // args_ 为刚才拷贝的参数值指针数组 slotObj_->call(object, args_); } else if (callFunction_ && method_offset_ <= object->metaObject()->methodOffset()) { callFunction_(object, QMetaObject::InvokeMetaMethod, method_relative_, args_); } else { QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method_offset_ + method_relative_, args_); } } template<typename Function, int N> struct Functor { template <typename SignalArgs, typename R> static void call(Function &f, void *, void **arg) { FunctorCall<typename Indexes<N>::Value, SignalArgs, R, Function>::call(f, arg); } }; template <typename, typename, typename, typename> struct FunctorCall; template <int... II, typename... SignalArgs, typename R, typename Function> struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, Function> { static void call(Function &f, void **arg) { f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]); } }; connect(tObj, &test::sgn5, this, [](QString _t1, QString t2, int age) { qDebug() << "Recv sgn5 in myTest"; qDebug() << "Recv sgn5 in myTest....." << _t1 << t2 << age; return 10; }, Qt::QueuedConnection);
最后经过一系列调用,会调用与信号连接的槽函数
2.3 阻塞队列Qt::BlockingQueuedConnection
if (receiverInSameThread) { qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: " "Sender is %s(%p), receiver is %s(%p)", sender->metaObject()->className(), sender, receiver->metaObject()->className(), receiver); } QSemaphore semaphore; QMetaCallEvent *ev = c->isSlotObject ? new QMetaCallEvent(c->slotObj, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore) : new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore); QCoreApplication::postEvent(receiver, ev); locker.unlock(); semaphore.acquire(); locker.relock(); continue;
阻塞队列不能在发送者与接收者不能在同一个线程中。因为是阻塞的,所以参数也无需拷贝,直接发送QMetaCallEvent到队列中。