您的位置:首页 > 编程语言 > Qt开发

深入理解QT的SIGNAL\SLOT机制(四):Connection结构

2017-12-20 10:54 351 查看
书接上文,本章讲述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函数说完了,看明白的童鞋应该会理解我在一开始说的观察者模式了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  qt SIGNAL SLOT