QT <源码笔记> 信号与槽

信号与槽

1、QT 信号槽功能由QObject提供,实现基于Qt 元对象系统,其文档描述为:
Signals and slots are made possible by Qt’s meta-object system
2、QObject 类为使用信号槽机制的基类,子类在private 中定义Q_OBJECT宏
3、元对象编译器(MOC)在预编译阶段解析定义有Q_OBJECT宏的源文件,并生成moc_xxx.cpp文件,该文件中包含信号与槽相关信息(名称、信号连接等)

QT文档描述:
The meta-object system is based on three things:
The QObject class provides a base class for objects that can take advantage of the meta-object system.
The Q_OBJECT macro inside the private section of the class declaration is used to enable meta-object features, such as dynamic properties, signals, and slots.
The Meta-Object Compiler (moc) supplies each QObject subclass with the necessary code to implement meta-object features.
The moc tool reads a C++ source file. If it finds one or more class declarations that contain the Q_OBJECT macro, it produces another C++ source file which contains the meta-object code for each of those classes. This generated source file is either #include’d into the class’s source file or, more usually, compiled and linked with the class’s implementation.


前言

一、Q_OBJECT

源代码定义在qobjectdefs.h 中如下(Qt6.0.2):

/* qmake ignore Q_OBJECT */
#define Q_OBJECT \
public: \
    QT_WARNING_PUSH \
    Q_OBJECT_NO_OVERRIDE_WARNING \
    static const QMetaObject staticMetaObject; \
    virtual const QMetaObject *metaObject() const; \
    virtual void *qt_metacast(const char *); \
    virtual int qt_metacall(QMetaObject::Call, int, void **); \
    QT_TR_FUNCTIONS \
private: \
    Q_OBJECT_NO_ATTRIBUTES_WARNING \
    Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
    QT_WARNING_POP \
    struct QPrivateSignal {}; \
    QT_ANNOTATE_CLASS(qt_qobject, "")

1、定义静态元对象 QMetaObject
2、获取QMetaObject 的虚函数
3、qt_metacall 元对象调用
4、qt_metacast :根据签名得到相关结构的指针
5、虚函数:
virtual const QMetaObject *metaObject() const;
virtual void *qt_metacast(const char *);
virtual int qt_metacall(QMetaObject::Call, int, void **);
MOC在生成的moc_xxx.cpp文件中实现 ,代码如下:

void Worker::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        auto *_t = static_cast<Worker *>(_o);
        Q_UNUSED(_t)
        switch (_id) {
        case 0: _t->resultReady((*reinterpret_cast< QString(*)>(_a[1]))); break;
        case 1: _t->sig_realAlgMsg((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
        case 2: _t->doWork((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
        case 3: _t->slot_checkRealAlgMsg(); break;
        default: ;
        }
    } else if (_c == QMetaObject::IndexOfMethod) {
        int *result = reinterpret_cast<int *>(_a[0]);
        {
            using _t = void (Worker::*)(QString );
            if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Worker::resultReady)) {
                *result = 0;
                return;
            }
        }
        {
            using _t = void (Worker::*)(int , QString );
            if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Worker::sig_realAlgMsg)) {
                *result = 1;
                return;
            }
        }
    }
}


QT_INIT_METAOBJECT const QMetaObject Worker::staticMetaObject = { {
    &QObject::staticMetaObject,
    qt_meta_stringdata_Worker.data,
    qt_meta_data_Worker,
    qt_static_metacall,
    nullptr,
    nullptr
} };


const QMetaObject *Worker::metaObject() const
{
    return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}

void *Worker::qt_metacast(const char *_clname)
{
    if (!_clname) return nullptr;
    if (!strcmp(_clname, qt_meta_stringdata_Worker.stringdata0))
        return static_cast<void*>(this);
    return QObject::qt_metacast(_clname);
}

int Worker::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 < 4)
            qt_static_metacall(this, _c, _id, _a);
        _id -= 4;
    } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
        if (_id < 4)
            *reinterpret_cast<int*>(_a[0]) = -1;
        _id -= 4;
    }
    return _id;
}

二、MOC

MOC:Meta-Object Compiler,“元对象编译器”,预编译时处理带有Q_OBJECT源文件,生成moc_xxx.cpp

生成的moc_xxx.cpp文件可以再cpp中#include 的方式使用,如移植Qt属性设置代码如下:

QT_END_NAMESPACE

#include "moc_qteditorfactory.cpp"
#include "qteditorfactory.moc"

在这里插入图片描述
在这里插入图片描述

1.QMetaObject

QT 文档描述如下:
A single QMetaObject instance is created for each QObject subclass that is used in an application, and this instance stores all the meta-information for the QObject subclass
翻译:
为应用程序中使用的每个QObject子类创建一个QMetaObject实例,并且该实例存储QObject子类的所有元信息。
className() returns the name of a class.
superClass() returns the superclass’s meta-object.
method() and methodCount() provide information about a class’s meta-methods (signals, slots and other invokable member functions).
enumerator() and enumeratorCount() and provide information about a class’s enumerators.
propertyCount() and property() provide information about a class’s properties.
constructor() and constructorCount() provide information about a class’s meta-constructors.
翻译:
className()返回类的名称。
superClass()返回父类的元对象。
method()和methodCount()提供有关类的元方法(信号,插槽和其他可调用成员函数)的信息。
enumerator()和enumeratorCount()并提供有关类的枚举数的信息。
propertyCount()和property()提供有关类的属性的信息。
Constructor()和ConstructorCount()提供有关类的元构造函数的信息。

2.Moc_xxx.cpp

1、qt_meta_data元数据

qt_meta_data元数据代码如下(示例):

static const uint qt_meta_data_Worker[] = {

 // content:
       8,       // revision 生成代码的moc版本号
       0,       // classname 类名索引
       0,    0, // classinfo 类信息索引
       4,   14, // methods 类中信号与槽数目
       0,    0, // properties 属性位置信息
       0,    0, // enums/sets 枚举位置信息
       0,    0, // constructors 构造函数位置信息
       0,       // flags
       2,       // signalCount 信号数量

 // signals: name, argc, parameters, tag, flags
       1,    1,   34,    2, 0x06 /* Public */,
       4,    2,   37,    2, 0x06 /* Public */,

 // slots: name, argc, parameters, tag, flags
       5,    2,   42,    2, 0x0a /* Public */,
       8,    0,   47,    2, 0x0a /* Public */,

 // signals: parameters
    QMetaType::Void, QMetaType::QString,    3,
    QMetaType::Void, QMetaType::Int, QMetaType::QString,    2,    2,

 // slots: parameters
    QMetaType::Void, QMetaType::QString, QMetaType::QString,    6,    7,
    QMetaType::Void,

       0        // eod
};

在这里插入图片描述

3、 signals 信号

moc 处理源文件时将信号函数在moc_xxx.cpp中实现示例如下:

// SIGNAL 0
void Worker::resultReady(QString _t1)
{
    void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(this, &staticMetaObject, 0, _a);
}

// SIGNAL 1
void Worker::sig_realAlgMsg(int _t1, QString _t2)
{
    void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
    QMetaObject::activate(this, &staticMetaObject, 1, _a);
}

信号声明:
在这里插入图片描述

4、 slots 槽

slots 标记槽函数, 在moc_xxx.cpp中有槽函数参数信息,示例如下:

 // slots: name, argc, parameters, tag, flags
       5,    2,   42,    2, 0x0a /* Public */,
       8,    0,   47,    2, 0x0a /* Public */,

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210519172411972.png#pic_center
宏slots 前须有 private 、public 、protected修饰,否则编译报错
在这里插入图片描述

5、 信号连接

QObject 定义了信号连接函数,根据参数不同,有不同定义,示例如下:

 static QMetaObject::Connection connect(const QObject *sender, const char *signal,
                        const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);

QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
                                         const QObject *receiver, const char *method,
                                         Qt::ConnectionType type)
{
    if (sender == nullptr || receiver == nullptr || signal == nullptr || method == nullptr) {
        qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
                  sender ? sender->metaObject()->className() : "(nullptr)",
                  (signal && *signal) ? signal + 1 : "(nullptr)",
                  receiver ? receiver->metaObject()->className() : "(nullptr)",
                  (method && *method) ? method + 1 : "(nullptr)");
        return QMetaObject::Connection(nullptr);
    }
    QByteArray tmp_signal_name;

    if (!check_signal_macro(sender, signal, "connect", "bind"))
        return QMetaObject::Connection(nullptr);
    const QMetaObject *smeta = sender->metaObject();
    const char *signal_arg = signal;
    ++signal; // skip code
    QArgumentTypeArray signalTypes;
    Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
    QByteArray signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
    int signal_index = QMetaObjectPrivate::indexOfSignalRelative(
            &smeta, signalName, signalTypes.size(), signalTypes.constData());
    if (signal_index < 0) {
        // check for normalized signatures
        tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
        signal = tmp_signal_name.constData() + 1;

        signalTypes.clear();
        signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
        smeta = sender->metaObject();
        signal_index = QMetaObjectPrivate::indexOfSignalRelative(
                &smeta, signalName, signalTypes.size(), signalTypes.constData());
    }
    if (signal_index < 0) {
        err_method_notfound(sender, signal_arg, "connect");
        err_info_about_objects("connect", sender, receiver);
        return QMetaObject::Connection(nullptr);
    }
    signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
    signal_index += QMetaObjectPrivate::signalOffset(smeta);

    QByteArray tmp_method_name;
    int membcode = extract_code(method);

    if (!check_method_code(membcode, receiver, method, "connect"))
        return QMetaObject::Connection(nullptr);
    const char *method_arg = method;
    ++method; // skip code

    QArgumentTypeArray methodTypes;
    QByteArray methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
    const QMetaObject *rmeta = receiver->metaObject();
    int method_index_relative = -1;
    Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
    switch (membcode) {
    case QSLOT_CODE:
        method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
                &rmeta, methodName, methodTypes.size(), methodTypes.constData());
        break;
    case QSIGNAL_CODE:
        method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
                &rmeta, methodName, methodTypes.size(), methodTypes.constData());
        break;
    }
    if (method_index_relative < 0) {
        // check for normalized methods
        tmp_method_name = QMetaObject::normalizedSignature(method);
        method = tmp_method_name.constData();

        methodTypes.clear();
        methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
        // rmeta may have been modified above
        rmeta = receiver->metaObject();
        switch (membcode) {
        case QSLOT_CODE:
            method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
                    &rmeta, methodName, methodTypes.size(), methodTypes.constData());
            break;
        case QSIGNAL_CODE:
            method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
                    &rmeta, methodName, methodTypes.size(), methodTypes.constData());
            break;
        }
    }

    if (method_index_relative < 0) {
        err_method_notfound(receiver, method_arg, "connect");
        err_info_about_objects("connect", sender, receiver);
        return QMetaObject::Connection(nullptr);
    }

    if (!QMetaObjectPrivate::checkConnectArgs(signalTypes.size(), signalTypes.constData(),
                                              methodTypes.size(), methodTypes.constData())) {
        qCWarning(lcConnect,
                  "QObject::connect: Incompatible sender/receiver arguments"
                  "\n        %s::%s --> %s::%s",
                  sender->metaObject()->className(), signal, receiver->metaObject()->className(),
                  method);
        return QMetaObject::Connection(nullptr);
    }

    int *types = nullptr;
    if ((type == Qt::QueuedConnection)
            && !(types = queuedConnectionTypes(signalTypes.constData(), signalTypes.size()))) {
        return QMetaObject::Connection(nullptr);
    }

#ifndef QT_NO_DEBUG
    QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
    QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
    check_and_warn_compat(smeta, smethod, rmeta, rmethod);
#endif
    QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
        sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
    return handle;
}

1、参数合法性判断
2、check_signal_macro 检测信号定义

static bool check_signal_macro(const QObject *sender, const char *signal,
                                const char *func, const char *op)
{
    int sigcode = extract_code(signal);
    if (sigcode != QSIGNAL_CODE) {
        if (sigcode == QSLOT_CODE)
            qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s", func, op,
                      sender->metaObject()->className(), signal + 1);
        else
            qCWarning(lcConnect, "QObject::%s: Use the SIGNAL macro to %s %s::%s", func, op,
                      sender->metaObject()->className(), signal);
        return false;
    }
    return true;
}
static int extract_code(const char *member)
{
    // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
    return (((int)(*member) - '0') & 0x3);
}

3、获取信号索引
int signal_index = QMetaObjectPrivate::indexOfSignalRelative
4、获取槽索引 QMetaObjectPrivate::indexOfSignalRelative
5、检查连接参数 QMetaObjectPrivate::checkConnectArgs
6、生成连接

 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
       sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
   return handle;
class Q_CORE_EXPORT QMetaObject::Connection {
   void *d_ptr; //QObjectPrivate::Connection*
   explicit Connection(void *data) : d_ptr(data) {  }
   friend class QObject;
   friend class QObjectPrivate;
   friend struct QMetaObject;
   bool isConnected_helper() const;
public:
   ~Connection();
   Connection();
   Connection(const Connection &other);
   Connection &operator=(const Connection &other);
#ifdef Q_QDOC
   operator bool() const;
#else
   // still using the restricted bool trick here, in order to support
   // code using copy-init (e.g. `bool ok = connect(...)`)
   typedef void *Connection::*RestrictedBool;
   operator RestrictedBool() const { return d_ptr && isConnected_helper() ? &Connection::d_ptr : nullptr; }
#endif

   Connection(Connection &&other) noexcept : d_ptr(qExchange(other.d_ptr, nullptr)) {}
   QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Connection)
   void swap(Connection &other) noexcept { qSwap(d_ptr, other.d_ptr); }
};

Connect 结构定义 QObjectPrivate,默认队列连接 因为
ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking

 struct Connection : public ConnectionOrSignalVector
    {
        // linked list of connections connected to slots in this object, next is in base class
        Connection **prev;
        // linked list of connections connected to signals in this object
        QAtomicPointer<Connection> nextConnectionList;
        Connection *prevConnectionList;

        QObject *sender;
        QAtomicPointer<QObject> receiver;
        QAtomicPointer<QThreadData> receiverThreadData;
        union {
            StaticMetaCallFunction callFunction;
            QtPrivate::QSlotObjectBase *slotObj;
        };
        QAtomicPointer<const int> argumentTypes;
        QAtomicInt ref_;
        uint id = 0;
        ushort method_offset;
        ushort method_relative;
        signed int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
        ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking
        ushort isSlotObject : 1;
        ushort ownArgumentTypes : 1;
        ushort isSingleShot : 1;
        Connection() : ref_(2), ownArgumentTypes(true) {
            //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
        }
        ~Connection();
        int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; }
        void ref() { ref_.ref(); }
        void freeSlotObject()
        {
            if (isSlotObject) {
                slotObj->destroyIfLastRef();
                isSlotObject = false;
            }
        }
        void deref()
        {
            if (!ref_.deref()) {
                Q_ASSERT(!receiver.loadRelaxed());
                Q_ASSERT(!isSlotObject);
                delete this;
            }
        }
    };
    // ConnectionList is a singly-linked list
    struct ConnectionList {
        QAtomicPointer<Connection> first;
        QAtomicPointer<Connection> last;
    };
 struct ConnectionOrSignalVector {
        union {
            // linked list of orphaned connections that need cleaning up
            ConnectionOrSignalVector *nextInOrphanList;
            // linked list of connections connected to slots in this object
            Connection *next;
        };

        static SignalVector *asSignalVector(ConnectionOrSignalVector *c)
        {
            if (reinterpret_cast<quintptr>(c) & 1)
                return reinterpret_cast<SignalVector *>(reinterpret_cast<quintptr>(c) & ~quintptr(1u));
            return nullptr;
        }
        static Connection *fromSignalVector(SignalVector *v) {
            return reinterpret_cast<Connection *>(reinterpret_cast<quintptr>(v) | quintptr(1u));
        }
    };

6、 信号触发

moc_xxx.cpp 中信号函数:

// SIGNAL 0
void Worker::resultReady(QString _t1)
{
    void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(this, &staticMetaObject, 0, _a);
}

信号触发实现:
static void activate(QObject *sender, int signal_index, void **argv);

void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
                          void **argv)
{
   int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);

   if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
       doActivate<true>(sender, signal_index, argv);
   else
       doActivate<false>(sender, signal_index, argv);
}
template <bool callbacks_enabled>
void doActivate(QObject *sender, int signal_index, void **argv)
{
    QObjectPrivate *sp = QObjectPrivate::get(sender);

    if (sp->blockSig)
        return;

    Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);

    if (sp->isDeclarativeSignalConnected(signal_index)
            && QAbstractDeclarativeData::signalEmitted) {
        Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
        QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
                                                signal_index, argv);
    }

    const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;

    void *empty_argv[] = { nullptr };
    if (!argv)
        argv = empty_argv;

    if (!sp->maybeSignalConnected(signal_index)) {
        // The possible declarative connection is done, and nothing else is connected
        if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
            signal_spy_set->signal_begin_callback(sender, signal_index, argv);
        if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
            signal_spy_set->signal_end_callback(sender, signal_index);
        return;
    }

    if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
        signal_spy_set->signal_begin_callback(sender, signal_index, argv);

    bool senderDeleted = false;
    {
    Q_ASSERT(sp->connections.loadAcquire());
    QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadRelaxed());
    QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();

    const QObjectPrivate::ConnectionList *list;
    if (signal_index < signalVector->count())
        list = &signalVector->at(signal_index);
    else
        list = &signalVector->at(-1);

    Qt::HANDLE currentThreadId = QThread::currentThreadId();
    bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();

    // We need to check against the highest connection id to ensure that signals added
    // during the signal emission are not emitted in this emission.
    uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
    do {
        QObjectPrivate::Connection *c = list->first.loadRelaxed();
        if (!c)
            continue;

        do {
            QObject * const receiver = c->receiver.loadRelaxed();
            if (!receiver)
                continue;

            QThreadData *td = c->receiverThreadData.loadRelaxed();
            if (!td)
                continue;

            bool receiverInSameThread;
            if (inSenderThread) {
                receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
            } else {
                // need to lock before reading the threadId, because moveToThread() could interfere
                QMutexLocker lock(signalSlotLock(receiver));
                receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
            }


            // determine if this connection should be sent immediately or
            // put into the event queue
            if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
                || (c->connectionType == Qt::QueuedConnection)) {
                queued_activate(sender, signal_index, c, argv);
                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);
                }

                if (c->isSingleShot && !QObjectPrivate::disconnect(c))
                    continue;

                QSemaphore semaphore;
                {
                    QBasicMutexLocker locker(signalSlotLock(receiver));
                    if (!c->isSingleShot && !c->receiver.loadAcquire())
                        continue;
                    QMetaCallEvent *ev = c->isSlotObject ?
                        new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
                        new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
                                           sender, signal_index, argv, &semaphore);
                    QCoreApplication::postEvent(receiver, ev);
                }
                semaphore.acquire();
                continue;
#endif
            }

            if (c->isSingleShot && !QObjectPrivate::disconnect(c))
                continue;

            QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);

            if (c->isSlotObject) {
                c->slotObj->ref();

                struct Deleter {
                    void operator()(QtPrivate::QSlotObjectBase *slot) const {
                        if (slot) slot->destroyIfLastRef();
                    }
                };
                const std::unique_ptr<QtPrivate::QSlotObjectBase, Deleter> obj{c->slotObj};

                {
                    Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, obj.get());
                    obj->call(receiver, argv);
                }
            } 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 method_relative = c->method_relative;
                const auto callFunction = c->callFunction;
                const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
                if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
                    signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);

                {
                    Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
                    callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
                }

                if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
                    signal_spy_set->slot_end_callback(receiver, methodIndex);
            } else {
                const int method = c->method_relative + c->method_offset;

                if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
                    signal_spy_set->slot_begin_callback(receiver, method, argv);
                }

                {
                    Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
                    QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
                }

                if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
                    signal_spy_set->slot_end_callback(receiver, method);
            }
        } while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);

    } while (list != &signalVector->at(-1) &&
        //start over for all signals;
        ((list = &signalVector->at(-1)), true));

        if (connections->currentConnectionId.loadRelaxed() == 0)
            senderDeleted = true;
    }
    if (!senderDeleted) {
        sp->connections.loadRelaxed()->cleanOrphanedConnections(sender);

        if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
            signal_spy_set->signal_end_callback(sender, signal_index);
    }
}

7、 槽响应

qt_static_metacall实现槽函数调用:
示例代码如下:

void Worker::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        auto *_t = static_cast<Worker *>(_o);
        Q_UNUSED(_t)
        switch (_id) {
        case 0: _t->resultReady((*reinterpret_cast< QString(*)>(_a[1]))); break;
        case 1: _t->sig_realAlgMsg((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
        case 2: _t->doWork((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
        case 3: _t->slot_checkRealAlgMsg(); break;
        default: ;
        }
    } else if (_c == QMetaObject::IndexOfMethod) {
        int *result = reinterpret_cast<int *>(_a[0]);
        {
            using _t = void (Worker::*)(QString );
            if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Worker::resultReady)) {
                *result = 0;
                return;
            }
        }
        {
            using _t = void (Worker::*)(int , QString );
            if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Worker::sig_realAlgMsg)) {
                *result = 1;
                return;
            }
        }
    }
}

总结

参考:
https://blog.51cto.com/u_9291927/2070348
https://blog.csdn.net/chengkeke366/article/details/109500723
https://blog.csdn.net/ddllrrbb/article/details/88374350?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值