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完