本文主要对我翻译的那篇博文中关于connection的建立过程做一些补充说明(那篇博文在这儿:http://blog.csdn.net/newthinker_wei/article/details/22785763)。
下面先看几个重要的成员变量和几个数据类型(类或结构体)的定义。
class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
...... ......
// QObjectPrivate中的几个结构体类型的定义:
struct Connection
{
QObject *sender;
QObject *receiver;
...... ......
// The next pointer for the singly-linked ConnectionList
Connection *nextConnectionList;
//senders linked list
Connection *next;
Connection **prev;
...... ......
ushort method_offset;
ushort method_relative;
uint signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
ushort isSlotObject : 1;
ushort ownArgumentTypes : 1;
......
int method() const { return method_offset + method_relative; }
......
};
// ConnectionList is a singly-linked list
struct ConnectionList
{
ConnectionList() : first(0), last(0) {}
Connection *first;
Connection *last;
};
struct Sender
{
QObject *sender;
int signal;
int ref;
};
...... ......
// QObjectPrivate中的几个重要成员变量的定义:
QObjectConnectionListVector *connectionLists;
// QObjectConnectionListVector的定义在下一段代码中给出。
// QObjectConnectionListVector是以QObjectPrivate::ConnectionList为基础类型的
// Vector容器。每一个ConnectionList有一个first和一个last指针。
/*
This vector contains the all connections from an object.
Each object may have one vector containing the lists of
connections for a given signal. The index in the vector correspond
to the signal index. The signal index is the one returned by
QObjectPrivate::signalIndex (not QMetaObject::indexOfSignal).
Negative index means connections to all signals.
This vector is protected by the object mutex (signalSlotMutexes())
Each Connection is also part of a 'senders' linked list. The mutex
of the receiver must be locked when touching the pointers of this
linked list.
*/
Connection *senders; // linked list of connections connected to this object
Sender *currentSender; // object currently activating the object
...... ......
};
QObjectConnectionListVector的定义:
class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList>
{
public:
bool orphaned; //the QObject owner of this vector has been destroyed while the vector was inUse
bool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet
int inUse; //number of functions that are currently accessing this object or its connections
QObjectPrivate::ConnectionList allsignals;
QObjectConnectionListVector()
: QVector<QObjectPrivate::ConnectionList>(), orphaned(false), dirty(false), inUse(0)
{ }
QObjectPrivate::ConnectionList &operator[](int at)
{
if (at < 0)
return allsignals;
return QVector<QObjectPrivate::ConnectionList>::operator[](at);
}
};
可见QObjectConnectionListVector是从QVector模板类继承而来。这里不再贴出QVector的定义,只给出QtAssistant中对QVector模板类的介绍:
The QVector class is a templateclass that provides a dynamic array.
QVector<T> is one of Qt'sgeneric containerclasses. It stores its items in adjacent(相邻的)memory locations and provides fast index-based access.
看了上面几个定义,现在可以了解connect和disconnect的过程了。
每个QObject对象都有一个QObjectConnectionListVector结构,这是一个Vector容器,它里面的基本单元都是ConnectionList类型的数据,ConnectionList的个数与该QObject对象的signal个数相同。每个ConnectionList对应一个信号,它记录了连接到这个信号上的所有连接。前面已经看到ConnectionList的定义中有两个重要成员:first和last,他们都是Connection 类型的指针,分别指向连接到这个信号上的第一个和最后一个连接。所有连接到这个信号上的连接以单向链表的方式组织了起来,Connection结构体中的nextConnectionList成员就是用来指向这个链表中的下一个连接的。
同时,每个QObject对象还有一个senders成员,senders是一个Connection类型的指针,senders本身也是一个链表的头结点,这个链表中的所有结点都是连接到这个QObject对象上的某个槽的连接。不过这个链表跟上一段提到的链表可不是同一个!虽然他们可能有一些共同结点!下面详细说明。
每一个Connection对象都同时处于两个链表当中。其中一个是以Connection的nextConnectionList成员组织起来的单向链表,这个单项链表中每个结点的共同点是,他们都依赖于同一个QObject对象的同一个信号,这个链表的头结点就是这个信号对应的ConnectionList结构中的first;另一个链表是以Connection的next和prev成员组织起来的双向链表,这个双向链表中每个结点的共同点是,他们的槽都在同一个QObject对象上,这个链表的头结点就是这个Qobject对象的sender。这两个链表会有交叉(共同结点),但他们有不同的链接指针,所以不是同一个链表。
知道了这些,再来理解connect和disconnect就容易了。Connect的时候,就是先new一个Connection对象出来,设置好这个连接的信息后,将它分别添加到上面提到的两个链表中;disconnect的时候,就从从这两个链表中将它移除,然后delete掉。而当一个QObject对象被销毁的时候,它的sender指针指向的那个双向链表中的所有连接都会被逐个移除!
*******************************************************
讨论一下另一个不相关的问题:
写到这里正好附加一段说明。不知道有没有朋友注意到,我们在Qt开发过程中经常用到的connect函数,它的返回类型也是Connection。但是,那个Connection是QMetaObject命名域中的Connection类,而不是我们上面一直讨论的QObjectPravite命名域中的那个。那QMetaObject:: Connection类中包含哪些信息呢?它跟QObjectPravite::Connection又有何关系?
下面看QMetaObject::Connection的定义。可以看出,QMetaObject::Connection的第一个成员d_ptr就是一个QObjectPravite::Connection指针,所以QMetaObject::Connection已经包含了QObjectPravite::Connection类中的所有特性。
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;
public:
~Connection();
Connection();
Connection(const Connection &other);
Connection &operator=(const Connection &other);
#ifdef Q_QDOC
operator bool() const;
#else
typedef void *Connection::*RestrictedBool;
operator RestrictedBool() const { return d_ptr ? &Connection::d_ptr : 0; }
#endif
#ifdef Q_COMPILER_RVALUE_REFS
inline Connection(Connection &&o) : d_ptr(o.d_ptr) { o.d_ptr = 0; }
inline Connection &operator=(Connection &&other)
{ qSwap(d_ptr, other.d_ptr); return *this; }
#endif
};