QT4.8.6 connect函数代码解析

QT代码版本:4.8.6

工作两年了,这个函数真的用吐了,早想看看源码是怎么实现的了,现在总结一下。

相关思维

自顶向下,不要老想着上去就从connect代码去看,然后穷究每个细节,那样不仅累,也很难坚持。计算机软件是讲究分层的,从上到下一层层的看,先从类之间的关系入手,一层层来,最后才是那些细节,这时候答案也就呼之欲出了。
从数据成员入手,成员函数为辅。看清各个类之间的数据联系

相关类

QObject

众所周知,connect函数是QObject的,所以需要先了解QObject都跟哪些类有联系,看QObject.h中怎么定义的QObject(汉字注释是我写的)。其实也就各种成员函数和两个成员数据。

    QScopedPointer<QObjectData> d_ptr;          //这是一成员变量

    static const QMetaObject staticQtMetaObject;        //这还一个

通过这两个成员的类型,能得出一个结论:object的大部分功能应该是通过QObjectData和QMetaObject 去起作用的。注:QScopedPointer,是个功能性的模板类跟本文没多大关系,不介绍
那就再看看这两个类都有啥呗

QObjectData

class
#if defined(__INTEL_COMPILER) && defined(Q_OS_WIN)
Q_CORE_EXPORT
#endif
QObjectData {
public:
    virtual ~QObjectData() = 0;
    QObject *q_ptr;                     //有啥用?
    QObject *parent;                    //父对象的指针
    QObjectList children;               //子对象指针

    uint isWidget : 1;                  //是不是窗口
    uint pendTimer : 1;                //看不懂
    uint blockSig : 1;                  //是不是阻塞信号
    uint wasDeleted : 1;                //是不是删了
    uint ownObjectName : 1;             //自己叫啥名
    uint sendChildEvents : 1;           //是不是跟子对象发事件
    uint receiveChildEvents : 1;        //是不是接受子对象的事件
    uint inEventHandler : 1; //only used if QT_JAMBI_BUILD      //是不是在处理事件
    uint inThreadChangeEvent : 1;                               //是不是在处理线程改变事件      看来这事件挺重要啊
    uint hasGuards : 1; //true iff there is one or more QPointer attached to this object
    uint unused : 22;               //??
    int postedEvents;               //发送多少事件了?
    QMetaObject *metaObject; // assert dynamic          //元数据  感觉这个有用
};

要是看看QOject的成员函数,就发现QOjectData的成员大部分都能跟QOject的成员函数对上( 注:像这种 uint inThreadChangeEvent : 1; 申明成员的方式,那个1不是默认值,是位域,相关知识请自行百度,跟信号槽没关系。 ),也就是说把QObject需要用到的数据都封装了一下。
看下来感觉就 metaObject有用。

QMetaObject

这个才是重中之重
它的数据成员如下,只是数据成员啊 没放成员函数

struct Q_CORE_EXPORT QMetaObject
{
struct { // private data
        const QMetaObject *superdata;
        const char *stringdata;
        const uint *data;
        const void *extradata;
    } d;
}

啊这。。。这看不出来了啥啊

但有两点能确定:
1 他是个结构体
2 它只有一个成员d

d结构体中也没啥东西啊,结合成员函数看看

int QMetaObject::methodCount() const        //看名字是说返回有多少个函数
{
    int n = priv(d.data)->methodCount;      //返回自己的函数数量
    const QMetaObject *m = d.superdata;     //父类
    while (m) {
        n += priv(m->d.data)->methodCount;      //递归往上加 一直找到根节点
        m = m->d.superdata;
    }
    return n;
}

看这代码有两点值得注意:
1 data比较重要
2 用了一个priv函数

priv函数代码如下:

static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }

就是转一下指针

这就说明data指向QMetaObjectPrivate这个对象

QMetaObjectPrivate

QMetaObjectPrivate的数据成员如下

struct QMetaObjectPrivate
{
    int revision;
    int className;
    int classInfoCount, classInfoData;
    int methodCount, methodData;
    int propertyCount, propertyData;
    int enumeratorCount, enumeratorData;
    int constructorCount, constructorData; //since revision 2
    int flags; //since revision 3
    int signalCount; //since revision 4
}

这都能跟QMetaObject的函数对上,可问题是怎么知道的呢?怎么知道他的类名,他有几个函数?运行时这些都没了,除非提前设好,没错,就是提前设好的,编译时弄好的。
答:编译时先使用qt的moc编译器先编一波,把谁继承QObject类找到,然后找到信号槽,自动生成moc_类名的文件,接下来就是解析moc文件了

moc文件

Q_OBJECT宏

#define Q_OBJECT \
public: \
    Q_OBJECT_CHECK \
    static const QMetaObject staticMetaObject; \
    Q_OBJECT_GETSTATICMETAOBJECT \
    virtual const QMetaObject *metaObject() const; \
    virtual void *qt_metacast(const char *); \
    QT_TR_FUNCTIONS \
    virtual int qt_metacall(QMetaObject::Call, int, void **); \
private: \
    Q_DECL_HIDDEN static const QMetaObjectExtraData staticMetaObjectExtraData; \
    Q_DECL_HIDDEN static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);

自己写的demo

这是我写的一个demo类

#ifndef CONNECTDEMO_H
#define CONNECTDEMO_H

#include <QObject>

class ConnectDemo : public QObject
{
    Q_OBJECT
public:
    explicit ConnectDemo(QObject *parent = 0);
    ~ConnectDemo();

signals:
    void sig();
public slots:
    void slt();
};

#endif // CONNECTDEMO_H

他的moc文件部分内容

static const uint qt_meta_data_ConnectDemo[] = {

 // content:
       6,       // revision
       0,       // classname
       0,    0, // classinfo
       2,   14, // methods
       0,    0, // properties
       0,    0, // enums/sets
       0,    0, // constructors
       0,       // flags
       1,       // signalCount

 // signals: signature, parameters, type, tag, flags
      13,   12,   12,   12, 0x05,

 // slots: signature, parameters, type, tag, flags
      19,   12,   12,   12, 0x0a,

       0        // eod
};

看注释这就能对上了

2023.12.17 未完待续

成员解析

可以看到 声明了2个成员和4个成员函数
staticMetaObject 成员如下

const QMetaObject ConnectDemo::staticMetaObject = {		
    { &QObject::staticMetaObject, qt_meta_stringdata_ConnectDemo,
      qt_meta_data_ConnectDemo, &staticMetaObjectExtraData }
};
static const char qt_meta_stringdata_ConnectDemo[] = {
    "ConnectDemo\0\0sig()\0slt()\0"
};
static const uint qt_meta_data_ConnectDemo[] = {

 // content:
       6,       // revision
       0,       // classname
       0,    0, // classinfo
       2,   14, // methods
       0,    0, // properties
       0,    0, // enums/sets
       0,    0, // constructors
       0,       // flags
       1,       // signalCount

 // signals: signature, parameters, type, tag, flags
      13,   12,   12,   12, 0x05,

 // slots: signature, parameters, type, tag, flags
      19,   12,   12,   12, 0x0a,

       0        // eod
};

看看QMetaObject 的数据结构,发现是能对上的
其中 QObject::staticMetaObject,主要用来根据信号槽名字找索引时用的,这样做就相当于建立了一个链表,子类指向父类

相关函数

connect

bool QObject::connect(const QObject *sender, const char *signal,
                      const QObject *receiver, const char *method,
                      Qt::ConnectionType type)
{
    {
        const void *cbdata[] = { sender, signal, receiver, method, &type };
        if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))
            return true;
    }

#ifndef QT_NO_DEBUG
    bool warnCompat = true;
#endif
    if (type == Qt::AutoCompatConnection) {
        type = Qt::AutoConnection;
#ifndef QT_NO_DEBUG
        warnCompat = false;
#endif
    }

    if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {
        qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",
                 sender ? sender->metaObject()->className() : "(null)",
                 (signal && *signal) ? signal+1 : "(null)",
                 receiver ? receiver->metaObject()->className() : "(null)",
                 (method && *method) ? method+1 : "(null)");
        return false;
    }
    QByteArray tmp_signal_name;

    if (!check_signal_macro(sender, signal, "connect", "bind"))
        return false;
    const QMetaObject *smeta = sender->metaObject();		
    const char *signal_arg = signal;
    ++signal; //skip code
    int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);		//
    if (signal_index < 0) {
        // check for normalized signatures
        tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
        signal = tmp_signal_name.constData() + 1;

        smeta = sender->metaObject();
        signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
    }
    if (signal_index < 0) {
        // re-use tmp_signal_name and signal from above

        smeta = sender->metaObject();
        signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);
    }
    if (signal_index < 0) {
        err_method_notfound(sender, signal_arg, "connect");
        err_info_about_objects("connect", sender, receiver);
        return false;
    }
    signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
    int signalOffset, methodOffset;
    computeOffsets(smeta, &signalOffset, &methodOffset);
    int signal_absolute_index = signal_index + methodOffset;
    signal_index += signalOffset;

    QByteArray tmp_method_name;
    int membcode = extract_code(method);

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

    const QMetaObject *rmeta = receiver->metaObject();
    int method_index_relative = -1;
    switch (membcode) {
    case QSLOT_CODE:
        method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
        break;
    case QSIGNAL_CODE:
        method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
        break;
    }

    if (method_index_relative < 0) {
        // check for normalized methods
        tmp_method_name = QMetaObject::normalizedSignature(method);
        method = tmp_method_name.constData();

        // rmeta may have been modified above
        rmeta = receiver->metaObject();
        switch (membcode) {
        case QSLOT_CODE:
            method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
            if (method_index_relative < 0)
                method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true);
            break;
        case QSIGNAL_CODE:
            method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
            if (method_index_relative < 0)
                method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true);
            break;
        }
    }

    if (method_index_relative < 0) {
        err_method_notfound(receiver, method_arg, "connect");
        err_info_about_objects("connect", sender, receiver);
        return false;
    }

    if (!QMetaObject::checkConnectArgs(signal, method)) {
        qWarning("QObject::connect: Incompatible sender/receiver arguments"
                 "\n        %s::%s --> %s::%s",
                 sender->metaObject()->className(), signal,
                 receiver->metaObject()->className(), method);
        return false;
    }

    int *types = 0;
    if ((type == Qt::QueuedConnection)
            && !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes())))
        return false;

#ifndef QT_NO_DEBUG
    if (warnCompat) {
        QMetaMethod smethod = smeta->method(signal_absolute_index);
        QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
        check_and_warn_compat(smeta, smethod, rmeta, rmethod);
    }
#endif
    if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index_relative, rmeta ,type, types))
        return false;
    const_cast<QObject*>(sender)->connectNotify(signal - 1);
    return true;
}

示例代码
在这里插入图片描述
调试时各个参数如下
在这里插入图片描述

需要注意的画上了,就是signal和method参数,为啥都加了个数呢?
答:那肯定是那两个宏起作用了呗

# define SLOT(a)     qFlagLocation("1"#a QLOCATION)
# define SIGNAL(a)   qFlagLocation("2"#a QLOCATION)
const char *qFlagLocation(const char *method)
{
    QThreadData::current()->flaggedSignatures.store(method);
    return method;
}

这qFlagLocation感觉跟信号槽没啥关系,总之就是给传进去的参数加了个前缀

先说下connect函数的整体思路:
1根据函数名字找索引值(用到的成员就是QMetaObject ConnectDemo::staticMetaObject)
2根据索引值建立连接
就这么简单,无外乎找的时候步骤多一些而已。
一步步看看吧
在这里插入图片描述
跟信号槽没啥直接关系。

在这里插入图片描述
简单的检查而已

在这里插入图片描述

这三句可有用了
1) const QMetaObject *smeta = sender->metaObject();
因为metaObject函数是虚函数,所以根据多态,这里获取的是sender这个对象的真正类的staticMetaObject。
证据如下:
在这里插入图片描述
在这里插入图片描述
2)const char *signal_arg = signal;
++signal; //skip code
人家自己注释已经说的比较明白了,就是跳过刚才SIGNAL宏加上的1
证据
在这里插入图片描述

3)int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
这句就比较重要了,这个函数就起到了根据字符串找索引的作用

int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
                                              const char *signal,
                                              bool normalizeStringData)
{
    int i = indexOfMethodRelative<MethodSignal>(baseObject, signal, normalizeStringData);
#ifndef QT_NO_DEBUG
    const QMetaObject *m = *baseObject;
    if (i >= 0 && m && m->d.superdata) {
        int conflict = m->d.superdata->indexOfMethod(signal);
        if (conflict >= 0)
            qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s",
                     signal, m->d.superdata->d.stringdata, m->d.stringdata);
    }
#endif
    return i;
}

这函数只是封装了一下,indexOfMethodRelative这个才是重要的

template<int MethodType>
static inline int indexOfMethodRelative(const QMetaObject **baseObject,
                                        const char *method,
                                        bool normalizeStringData)
{
    for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) {
        int i = (MethodType == MethodSignal && priv(m->d.data)->revision >= 4)
                ? (priv(m->d.data)->signalCount - 1) : (priv(m->d.data)->methodCount - 1);
        const int end = (MethodType == MethodSlot && priv(m->d.data)->revision >= 4)
                        ? (priv(m->d.data)->signalCount) : 0;
        if (!normalizeStringData) {
            for (; i >= end; --i) {
                const char *stringdata = m->d.stringdata + m->d.data[priv(m->d.data)->methodData + 5*i];
                if (method[0] == stringdata[0] && strcmp(method + 1, stringdata + 1) == 0) {
                    *baseObject = m;
                    return i;
                }
            }
        } else if (priv(m->d.data)->revision < 5) {
            for (; i >= end; --i) {
                const char *stringdata = (m->d.stringdata + m->d.data[priv(m->d.data)->methodData + 5 * i]);
                const QByteArray normalizedSignature = QMetaObject::normalizedSignature(stringdata);
                if (normalizedSignature == method) {
                    *baseObject = m;
                    return i;
                }
            }
        }
    }
    return -1;
}


for (const QMetaObject *m = *baseObject; m; m = m->d.superdata)
这句就是遍历链表用的,链表就是继承关系,像我这个ConnectDemo,继承了QObject。那就是ConnectDemo->QObject,为啥要这样?因为信号是可以被继承的,这操作6.

这个函数有很大的用

static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }

虽然只是个类型转换,但也很有用
他把这个数组转了

static const uint qt_meta_data_ConnectDemo[] = {

 // content:
       6,       // revision
       0,       // classname
       0,    0, // classinfo
       2,   14, // methods
       0,    0, // properties
       0,    0, // enums/sets
       0,    0, // constructors
       0,       // flags
       1,       // signalCount

 // signals: signature, parameters, type, tag, flags
      13,   12,   12,   12, 0x05,

 // slots: signature, parameters, type, tag, flags
      19,   12,   12,   12, 0x0a,

       0        // eod
};

二者结合一下,就清晰了

struct QMetaObjectPrivate
{
    int revision;
    int className;
    int classInfoCount, classInfoData;
    int methodCount, methodData;
    int propertyCount, propertyData;
    int enumeratorCount, enumeratorData;
    int constructorCount, constructorData; //since revision 2
    int flags; //since revision 3
    int signalCount; //since revision 4

转了,但又不全是,这技巧,啧啧太棒了。那后面的数干啥有?
接着看,
在这里插入图片描述
就在这句话上呢

在这里插入图片描述
这哪来的?
在这里插入图片描述
那它加的是啥?当然是这个了
在这里插入图片描述
为啥是13?数数下面字符数组qt_meta_stringdata_ConnectDemo下标13是哪个,是“s”,“sig()“的”s”。
结果一目了然了
在这里插入图片描述
i等0是因为我这个demo只有一个信号,所以是0。
在这里插入图片描述
我另加了一个,再把参数改下,就变成1了
接着回去看connect函数,啊对了indexOfSignalRelative这函数不还有第三个参数嘛 我没咋考察,意义不大,跟咱日常用的信号槽没啥关联
在这里插入图片描述
一些检查,意义不大

在这里插入图片描述
signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
这句没啥大用,好像跟一个比较小众的用法有关系,(不用穷究每个细节,把最核心的搞明白就行)

    int signalOffset, methodOffset;
    computeOffsets(smeta, &signalOffset, &methodOffset);
    int signal_absolute_index = signal_index + methodOffset;
    signal_index += signalOffset;

算偏移,然后加上

static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset)
{
    *signalOffset = *methodOffset = 0;
    const QMetaObject *m = metaobject->d.superdata;
    while (m) {
        const QMetaObjectPrivate *d = QMetaObjectPrivate::get(m);
        *methodOffset += d->methodCount;
        *signalOffset += (d->revision >= 4) ? d->signalCount : d->methodCount;
        /*Before Qt 4.6 (revision 4), the signalCount information was not generated by moc.
           so for compatibility we consider all the method as slot for old moc output*/
        m = m->d.superdata;
    }
}

就是一直往回捯,捯到祖坟QObject 上去,然后累加每个祖宗的信号数量和函数(这里说的是信号和槽函数加一起的数量)

在这里插入图片描述
看,由0变2了,为啥要加?
答:因为父类的信号也会被继承啊,0是相对当前类的,2是父类的,加一起才是你这信号真正的索引下标,要不你想想,光一个0,谁知道是你的还是你哪个父类的?
接下来是查槽函数索引
在这里插入图片描述
和查信号差不多
extract_code函数说一下,就是把宏前面加的那个数提出来,提出来供下面使用。

static int extract_code(const char *member)
{
    // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
    return (((int)(*member) - '0') & 0x3);
}

在这里插入图片描述

因为信号与信号也能相连,所以做做特殊处理,判断标准就是membcode,上面提出来的那个数。
运行结果

在这里插入图片描述
我看是因为QT是把信号都放前面导致的,我这demo就一个信号一个槽。
在这里插入图片描述
一些检查 没啥关系
在这里插入图片描述
见明知意,查信号与槽的参数对不对的上(咋不早检查呢?)

bool QMetaObject::checkConnectArgs(const char *signal, const char *method)
{
    const char *s1 = signal;
    const char *s2 = method;
    while (*s1++ != '(') { }                        // scan to first '('
    while (*s2++ != '(') { }
    if (*s2 == ')' || qstrcmp(s1,s2) == 0)        // method has no args or
        return true;                                //   exact match
    int s1len = qstrlen(s1);
    int s2len = qstrlen(s2);
    if (s2len < s1len && strncmp(s1,s2,s2len-1)==0 && s1[s2len-1]==',')
        return true;                                // method has less args
    return false;
}

就是个字符串比对的工作

在这里插入图片描述
还是个检查的工作
以上就是根据信号和槽的名字找索引的代码了,但有个点,就是槽为啥不累加上?留个疑问吧

下面连接上就行了
重点是这句
在这里插入图片描述
未完待续 20240511 22:45

bool QMetaObjectPrivate::connect函数代码如下

bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
                                 const QObject *receiver, int method_index,
                                 const QMetaObject *rmeta, int type, int *types)
{
    QObject *s = const_cast<QObject *>(sender);
    QObject *r = const_cast<QObject *>(receiver);

    int method_offset = rmeta ? rmeta->methodOffset() : 0;
    QObjectPrivate::StaticMetaCallFunction callFunction =
        (rmeta && QMetaObjectPrivate::get(rmeta)->revision >= 6 && rmeta->d.extradata)
        ? reinterpret_cast<const QMetaObjectExtraData *>(rmeta->d.extradata)->static_metacall : 0;

    QOrderedMutexLocker locker(signalSlotLock(sender),
                               signalSlotLock(receiver));

    if (type & Qt::UniqueConnection) {
        QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
        if (connectionLists && connectionLists->count() > signal_index) {
            const QObjectPrivate::Connection *c2 =
                (*connectionLists)[signal_index].first;

            int method_index_absolute = method_index + method_offset;

            while (c2) {
                if (c2->receiver == receiver && c2->method() == method_index_absolute)
                    return false;
                c2 = c2->nextConnectionList;
            }
        }
        type &= Qt::UniqueConnection - 1;
    }

    QObjectPrivate::Connection *c = new QObjectPrivate::Connection;
    c->sender = s;
    c->receiver = r;
    c->method_relative = method_index;
    c->method_offset = method_offset;
    c->connectionType = type;
    c->argumentTypes = types;
    c->nextConnectionList = 0;
    c->callFunction = callFunction;

    QT_TRY {
        QObjectPrivate::get(s)->addConnection(signal_index, c);
    } QT_CATCH(...) {
        delete c;
        QT_RETHROW;
    }

    c->prev = &(QObjectPrivate::get(r)->senders);
    c->next = *c->prev;
    *c->prev = c;
    if (c->next)
        c->next->prev = &c->next;

    QObjectPrivate *const sender_d = QObjectPrivate::get(s);
    if (signal_index < 0) {
        sender_d->connectedSignals[0] = sender_d->connectedSignals[1] = ~0;
    } else if (signal_index < (int)sizeof(sender_d->connectedSignals) * 8) {
        sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f));
    }

    return true;
}
 	QObject *s = const_cast<QObject *>(sender);
    QObject *r = const_cast<QObject *>(receiver);

强转一下,意义不大

 int method_offset = rmeta ? rmeta->methodOffset() : 0;

这句是获得从QObject到这的函数偏移量

int QMetaObject::methodOffset() const
{
    int offset = 0;
    const QMetaObject *m = d.superdata;
    while (m) {
        offset += priv(m->d.data)->methodCount;
        m = m->d.superdata;
    }
    return offset;
}

这函数作用就是一级一级往上找,然后把函数数量累加。因为咱们的继承的是QObject,所以获得的是他的函数数量。
这是QObject的QMetaObjectPrivate

static const uint qt_meta_data_QObject[] = {

 // content:
       6,       // revision
       0,       // classname
       0,    0, // classinfo
       4,   14, // methods
       1,   34, // properties
       0,    0, // enums/sets
       2,   37, // constructors
       0,       // flags
       2,       // signalCount

 // signals: signature, parameters, type, tag, flags
       9,    8,    8,    8, 0x05,
      29,    8,    8,    8, 0x25,

 // slots: signature, parameters, type, tag, flags
      41,    8,    8,    8, 0x0a,
      55,    8,    8,    8, 0x08,

 // properties: name, type, flags
      90,   82, 0x0a095103,

 // constructors: signature, parameters, type, tag, flags
     108,  101,    8,    8, 0x0e,
     126,    8,    8,    8, 0x2e,

       0        // eod
};

所以应该是4
证据如下
在这里插入图片描述

 QObjectPrivate::StaticMetaCallFunction callFunction =
        (rmeta && QMetaObjectPrivate::get(rmeta)->revision >= 6 && rmeta->d.extradata)
        ? reinterpret_cast<const QMetaObjectExtraData *>(rmeta->d.extradata)->static_metacall : 0;

声明一个函数指针,这个很重点!!!!它一般是reinterpret_cast<const QMetaObjectExtraData *>(rmeta->d.extradata)->static_metacall这个值,是指向qt_static_metacall这个静态函数的,函数指针能够指向参数返回值一样的不同类的静态函数,可以。

在这里插入图片描述

 QOrderedMutexLocker locker(signalSlotLock(sender),
                               signalSlotLock(receiver));

声明一个锁,没啥意义

   if (type & Qt::UniqueConnection) {
        QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
        if (connectionLists && connectionLists->count() > signal_index) {
            const QObjectPrivate::Connection *c2 =
                (*connectionLists)[signal_index].first;

            int method_index_absolute = method_index + method_offset;

            while (c2) {
                if (c2->receiver == receiver && c2->method() == method_index_absolute)
                    return false;
                c2 = c2->nextConnectionList;
            }
        }
        type &= Qt::UniqueConnection - 1;
    }

对于这一种连接方式进行特殊化处理,意义不大。
接下来是重中之重

 QObjectPrivate::Connection *c = new QObjectPrivate::Connection;
    c->sender = s;
    c->receiver = r;
    c->method_relative = method_index;
    c->method_offset = method_offset;
    c->connectionType = type;
    c->argumentTypes = types;
    c->nextConnectionList = 0;
    c->callFunction = callFunction;

声明一个QObjectPrivate::Connection ,主要的成员就是sender (发送方),receiver(接收方) ,callFunction,method_index(槽函数相对位置) 。

    QT_TRY {
        QObjectPrivate::get(s)->addConnection(signal_index, c);
    } QT_CATCH(...) {
        delete c;
        QT_RETHROW;
    }

    c->prev = &(QObjectPrivate::get(r)->senders);
    c->next = *c->prev;
    *c->prev = c;
    if (c->next)
        c->next->prev = &c->next;

放到链表中

 QObjectPrivate *const sender_d = QObjectPrivate::get(s);
    if (signal_index < 0) {
        sender_d->connectedSignals[0] = sender_d->connectedSignals[1] = ~0;
    } else if (signal_index < (int)sizeof(sender_d->connectedSignals) * 8) {
        sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f));
    }
    return true;

没啥意义,结个尾而已
2024.5.15 22:13完

  • 20
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值