从源码角度分析Qt元对象系统2

简介: 从源码角度分析Qt元对象系统

从源码角度分析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到队列中。

目录
相关文章
|
19天前
Qt类结构分析
Qt类结构分析
42 3
|
1月前
|
存储 C++
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
|
19天前
|
API
Qt绘图之Paint系统
Qt绘图之Paint系统
34 2
|
1月前
|
存储 算法 C++
【C++】C++ QT实现Huffman编码器与解码器(源码+课程论文+文件)【独一无二】
【C++】C++ QT实现Huffman编码器与解码器(源码+课程论文+文件)【独一无二】
|
19天前
|
存储
从源码角度分析Qt元对象系统1
从源码角度分析Qt元对象系统
45 0
|
30天前
|
数据安全/隐私保护
【qt】获取主机信息系统
【qt】获取主机信息系统
12 0
|
2月前
|
数据安全/隐私保护 C++ 计算机视觉
Qt(C++)开发一款图片防盗用水印制作小工具
文本水印是一种常用的防盗用手段,可以将文本信息嵌入到图片、视频等文件中,用于识别和证明文件的版权归属。在数字化和网络化的时代,大量的原创作品容易被不法分子盗用或侵犯版权,因此加入文本水印成为了保护原创作品和维护知识产权的必要手段。 通常情况下,文本水印可以包含版权声明、制作者姓名、日期、网址等信息,以帮助识别文件的来源和版权归属。同时,为了增强防盗用效果,文本水印通常会采用字体、颜色、角度等多种组合方式,使得水印难以被删除或篡改,有效地降低了盗用意愿和风险。 开发人员可以使用图像处理技术和编程语言实现文本水印的功能,例如使用Qt的QPainter类进行文本绘制操作,将文本信息嵌入到图片中,
133 1
Qt(C++)开发一款图片防盗用水印制作小工具
|
30天前
|
监控 C++ 容器
【qt】MDI多文档界面开发
【qt】MDI多文档界面开发
39 0
|
11天前
|
16天前
|
C++
C++ Qt开发:QUdpSocket网络通信组件
QUdpSocket是Qt网络编程中一个非常有用的组件,它提供了在UDP协议下进行数据发送和接收的能力。通过简单的方法和信号,可以轻松实现基于UDP的网络通信。不过,需要注意的是,UDP协议本身不保证数据的可靠传输,因此在使用QUdpSocket时,可能需要在应用层实现一些机制来保证数据的完整性和顺序,或者选择在适用的场景下使用UDP协议。
53 2

推荐镜像

更多