書接上文,本章講述connection結構,這部分是信號和槽能發揮作用的核心部分,先來看兩個結構體:
struct Connection
{
QObject *sender;//信號發起者
QObject *receiver;//信號接收者
union {
StaticMetaCallFunction callFunction;//接受者的static_meatcall函數地址
QtPrivate::QSlotObjectBase *slotObj;
};
Connection *nextConnectionList;//以下三個域是用於連接
Connection *next;
Connection **prev;
...//省略
};
// ConnectionList is a singly-linked list
struct ConnectionList {
ConnectionList() : first(0), last(0) {}
Connection *first;
Connection *last;
};
用一張圖來表示:
在第三章的QMetaObjectPrivate::connect函數中3314行:
QObjectPrivate::get(s)->addConnection(signal_index, c.data());
我們根據s(也就是sender,本例中就是MyWidget對象),拿到s的實例,然後調用該實例的addConnection方法,將connection對象插入到connectionLists列表中。
這裏詳細講解以下addConnection391~405行:
391行:我們看到在connectionLists中查找具體的信號是按照下標查找的,所以時間複雜度O(1),我們的mysignal是存儲在0的位置,也就是說,每隔信號的index就是存儲在connectionLists中的位置,所以QObject::connect方法中要確定每隔信號的signal_index。
392-395行:是在操作具有首尾指針的單鏈表。
399行:每次插入之後要清空無用的connection,以保證鏈表中的所有connection都是有用的。
void QObjectPrivate::cleanConnectionLists()
{
if (connectionLists->dirty && !connectionLists->inUse) {
// remove broken connections
for (int signal = -1; signal < connectionLists->count(); ++signal) {
QObjectPrivate::ConnectionList &connectionList =
(*connectionLists)[signal];
// Set to the last entry in the connection list that was *not*
// deleted. This is needed to update the list's last pointer
// at the end of the cleanup.
QObjectPrivate::Connection *last = 0;
QObjectPrivate::Connection **prev = &connectionList.first;
QObjectPrivate::Connection *c = *prev;
while (c) {
if (c->receiver) {
last = c;
prev = &c->nextConnectionList;
c = *prev;
} else {
QObjectPrivate::Connection *next = c->nextConnectionList;
*prev = next;
c->deref();
c = next;
}
}
// Correct the connection list's last pointer.
// As conectionList.last could equal last, this could be a noop
connectionList.last = last;
}
connectionLists->dirty = false;
}
}
這段代碼就是去遍歷connectionLists,檢查每隔信號的dirty和inUse屬性,dirty表示disconnected,但是connection對象還存在,所以應該刪除,inUse是connect的引用計數,也就是說,如果當前connectionList對象已經不用,就要刪除。如果connection的receiver不空,保留,爲空,刪除。
繼續來看connect函數:
401行: c->prev = &(QObjectPrivate::get(c->receiver)->senders);
根據receiver拿到實體類,在拿到senders,這個senders不是發送者,是接受者的鏈表,是用來刪除的,也就是最上面圖結構的senders,一旦接受者被析構,這個接受者的鏈表會被依次刪除。
402~405行:操作鏈表,不在贅述。
到此爲止可以說把QObject::connect函數說完了,看明白的童鞋應該會理解我在一開始說的觀察者模式了。