#define Q_OBJECT \ public: \ Q_OBJECT_CHECK \ static const QMetaObject staticMetaObject; \ virtual const QMetaObject *metaObject() const; \ virtual void *qt_metacast(const char *); \ QT_TR_FUNCTIONS \ virtual int qt_metacall(QMetaObject::Call, int, void **); \ private:首先调用了 Q_OBJECT_CHECK (插入了一个 qt_check_for_QOBJECT_macro 的 template function),然后是全局常量 QMetaObject 对象,因此可以用 QClassname::staticMetaObject 直接访问,另外提供了两个接口函数 metaObject() 用于不同的 class 返回自己的 staticMetaObject、qt_metacast() 用于转换,我们在 moc 产生的文件里面可以找到这两个接口的实现,
const QMetaObject *Counter::metaObject() const { return &staticMetaObject; } void *Counter::qt_metacast(const char *_clname) { if (!_clname) return 0; if (!strcmp(_clname, qt_meta_stringdata_Counter)) return static_cast<void*>(const_cast< Counter*>(this)); return QObject::qt_metacast(_clname); }后者很明显,如果需要转换的名字 _clname 是自己的类名,就把自己的指针通过转换成 void* 传回去,否则调用 QOject::qt_metacast(),其实就是看是不是 QObject 了,否则就返回 0 了。另外 QT_TR_FUNCTIONS 是对应的 i18n 的函数,我们后面再看。最后还有一个 qt_metacall 的接口,实现如下
int Counter::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QObject::qt_metacall(_c, _id, _a); if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { switch (_id) { case 0: valueChanged((*reinterpret_cast< int(*)>(_a[1]))); break; case 1: setValue((*reinterpret_cast< int(*)>(_a[1]))); break; default: ; } _id -= 2; } return _id; }这个函数起到一个中间作用,可以间接的调用成员方法,我们来仔细看看 QMetaObject,同一个文件里面有该结构的定义,我们只看这一部分,
struct Q_CORE_EXPORT QMetaObject { const char *className() const; const QMetaObject *superClass() const; QObject *cast(QObject *obj) const; // ... struct { // private data const QMetaObject *superdata; const char *stringdata; const uint *data; const void *extradata; } d; } ;注意 Couter 类 QMetaObject 的初始化,
const QMetaObject Counter::staticMetaObject = { { &QObject::staticMetaObject, qt_meta_stringdata_Counter, qt_meta_data_Counter, 0 } } ;下面我们着重看看几个与 signal/slot 相关的代码,首先就是 [qt]/src/corelib/kernel/qobject.cpp 文件中关于 QObject::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; } // checking sender, receiver, compatability of signal and slot QMetaObject::connect(sender, signal_index, receiver, method_index, type, types); const_cast<QObject*>(sender)->connectNotify(signal - 1); return true; }这里首先调用了 QInternal 这个 namespace 里面 activateCallbacks 这个函数,然后根据 QMetaObject 信息检查了 sender、receiver 以及对应 signal/slots 的匹配性,此时已经把 signal/slot 字符串转换成为了对应的 index,然后调用 QMetaObject::connect() 完成连接,最后的 QObject::connectNotify() 以及另外的 QObject::disconnectNotify() 其实是一个 signal。QInternal::activaeCallback() 在 [qt]/src/corelib/global/qglobal.cpp 中定义,
bool QInternal::activateCallbacks(Callback cb, void **parameters) { Q_ASSERT_X(cb >= 0, "QInternal::activateCallback()", "Callback id must be a valid id"); QInternal_CallBackTable *cbt = global_callback_table(); if (cbt && cb < cbt->callbacks.size()) { QList<qInternalCallback> callbacks = cbt->callbacks[cb]; bool ret = false; for (int i=0; i<callbacks.size(); ++i) ret |= (callbacks.at(i))(parameters); return ret; } return false; }这可以看出来调用该函数去检查一个 global_callback_table(),如果查到一个匹配的 signal/slot 就返回 true,否则返回 false,换言之 QObject::connect() 通过这个函数判定需不需要调用 QMetaObject::connect 创建新的连接。这个 callback table 本质是什么呢?同一个文件里面有
struct QInternal_CallBackTable { QVector<QList<qInternalCallback> > callbacks; };所以,这是一个链表的动态数组(Orz... 本来以为就是个链表),而 qInternalCallback 是一个在 [qt]/src/corelib/global/qnamespace.h 中定义的函数指针,
typedef bool (*qInternalCallback)(void **);现在我们可以猜测到在 QMetaObject::connect() 调用中我们会维护这个 callback table。在 [qt]/src/corelib/kernel/qmetaobject.cpp 我们有幸找到了如下代码:
bool QMetaObject::connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type, int *types) { QObject *s = const_cast<QObject *<(sender); QObject *r = const_cast<QObject *<(receiver); QOrderedMutexLocker locker(&s->d_func()->threadData->mutex, &r->d_func()->threadData->mutex); #if defined(Q_CC_HPACC) && defined(QT_ARCH_PARISC) QObjectPrivate::Connection c; c.receiver = r; c.method = method_index; c.connectionType = type; c.argumentTypes = types; #else QObjectPrivate::Connection c = { r, method_index, type, Q_BASIC_ATOMIC_INITIALIZER(types) }; #endif s->d_func()->addConnection(signal_index, &c); r->d_func()->refSender(s, signal_index); if (signal_index < 0) sender->d_func()->connectedSignals = ~0u; else if (signal_index < 32) sender->d_func()->connectedSignals |= (1 << signal_index); return true; }这段代码中使用了防止多线程操作引起问题的 mutex,sender 和 receiver 双方都有一个结构来保证这个通讯机制,sender 是通过 addConnection,receiver 通过 refSender(),这里并没有我们猜测的 global callback table。现在我们有两个问题,一个是 sender 通过 addConnection() 和 receiver 通过 refSneder() 记录了一些什么,用什么数据结构储存,另一个是 global callback table 是做什么用的。
我们先来看看 global callback table,不难发现,该 table 是 QInternal 类(没有成员,提供了一个接口)的方法维护的,主要有 QInternal::registerCallback()、QInternal::unregisterCallback()、QInternal::activateCallbacks()、QInternal::callFunction(),意思我想都很清楚,可是 grep 了一圈,似乎只在某些调试部分看到了调用该函数的地方,莫非这是用来调试的代码?
我们来看看 QObject->d_func() 返回的是什么。
#define Q_DECLARE_PRIVATE(Class) \ inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(d_ptr); } \ inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(d_ptr); } \ friend class Class##Private; #define Q_DECLARE_PRIVATE_D(Dptr, Class) \ inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(Dptr); } \ inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(Dptr); } \ friend class Class##Private; #define Q_DECLARE_PUBLIC(Class) \ inline Class* q_func() { return static_cast<Class *>(q_ptr); } \ inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \ friend class Class; #define Q_D(Class) Class##Private * const d = d_func() #define Q_Q(Class) Class * const q = q_func()记得 QObject 的定义么?
class Q_CORE_EXPORT QObject { Q_OBJECT Q_PROPERTY(QString objectName READ objectName WRITE setObjectName) Q_DECLARE_PRIVATE(QObject)这样 QObject 通过 d_func() 返回 d_ptr 这个指针,这是怎么一回事呢?我们知道这个宏在 QObject 内部定义了一个 QObjectPrivate 的类,并且留下了一个指针
protected: QObjectData *d_ptr;在 QObject 构造的时候创建了这个对象,并在析构的时候释放,由于是 friend class,可以对 QObject 无限制访问,
QObject::QObject(QObject *parent) : d_ptr(new QObjectPrivate) QObject::~QObject() { Q_D(QObject); // clear all signal receivers emit destroyed(this); // clear all signal senders delete d; d_ptr = 0; }可见真正管理 signal/slots 的是 QObjectPrivate 类,下面是它的主要成员函数,
//constructor and destructor QObjectPrivate::QObjectPrivate(int version) ; QObjectPrivate::~QObjectPrivate() ; int *QObjectPrivate::setDeleteWatch(QObjectPrivate *d, int *w) ; void QObjectPrivate::resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch) ; void QObjectPrivate::sendPendingChildInsertedEvents() ; void QObjectPrivate::removePendingChildInsertedEvents(QObject *child) ; bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const ; QObjectList QObjectPrivate::receiverList(const char *signal) const ; QObjectList QObjectPrivate::senderList() ; // connection list manipulation void QObjectPrivate::addConnection(int signal, Connection *c) ; void QObjectPrivate::removeReceiver(int signal, QObject *receiver) ; void QObjectPrivate::cleanConnectionLists() ; // sender list manipulation void QObjectPrivate::refSender(QObject *sender, int signal) ; void QObjectPrivate::derefSender(QObject *sender, int signal) ; void QObjectPrivate::removeSender(QObject *sender, int signal) ; QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver, Sender *sender) ; void QObjectPrivate::resetCurrentSender(QObject *receiver, Sender *currentSender, Sender *previousSender) ; void QObjectPrivate::clearGuards(QObject *object) ;那么我们如何存储数据的呢?在 [qt]/src/corelib/kernel/qobject_p.h 里,有该类的声明,
class Q_CORE_EXPORT QObjectPrivate : public QObjectData { // ... public: QList至此,我们已经找到了 Qt 实现 signal/slot 机制的所有需要知道的东西。pendingChildInsertedEvents; struct Sender { QObject *sender; int signal; int ref; }; Sender *currentSender; QList<QPointer<QObject> > eventFilters; struct Connection { QObject *receiver; int method; uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking QBasicAtomicPointer<int> argumentTypes; }; typedef QList<Connection> ConnectionList; QObjectConnectionListVector *connectionLists; QList<Sender> senders; } ;
记得下面 moc 生成的代码
void Counter::valueChanged(int _t1) { void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) }; QMetaObject::activate(this, &staticMetaObject, 0, _a); }这里重要的就是 QMetaObject::activate() 函数,其实它就是依次激活 senders 里面的函数,
void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv) ; void QMetaObject::activate(QObject *sender, int signal_index, void **argv) ; void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, void **argv) ; void QMetaObject::activate(QObject *sender, const QMetaObject *m, int from_local_signal_index, int to_local_signal_index, void **argv) ;这里调用的是第三个,他们最终都是用第一个实现的,下面是实现的基本代码,
void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv) { if (sender->d_func()->blockSig) return; // ... for (int signal = from_signal_index; (signal >= from_signal_index && signal <= to_signal_index) || (signal == -2); (signal == to_signal_index ? signal = -2 : ++signal)) { int count = connectionLists->at(signal).count(); for (int i = 0; i < count; ++i) { // signal type and etc receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); // ... } //... } // ... --connectionLists->inUse; // ... }
我们来回顾一下,使用 Qt 实现 signal/slots 机制是通过继承 QObject,并在类声明时加入 Q_OBJECT,该宏嵌入一个 QMetaObject 作为整个类实现 Qt 的 RTTI 机制的基础。继承 QObject 的同时使得该类含有一个 d_ptr 指向 QObject 共有的一个友元类 QObjectPrivate,每一个对象都会创建一个 QObjectPrivate 的对象来管理自己 signal/slot。对用户而言,通过声明 signal 其实是实现一个 protected function,它由 moc 生成程序,而 slot 本身就是一般的函数。signal 和 slot 通过调用 QObject::connect()/disconnect() 连接/切断连接,该函数验证连接的合理性(通过 QMetaObject 里面存放的字符串信息,如类名、父类、signal 和 slot 名称和参数),然后调用 QMetaObject::connect() 该方法会使用 mutex 保证操作的线程稳定性,访问两个对象的 d_ptr 指向的 QObjectPrivate 对象,对 sender 添加 connectionLists(一个链表),对 receiver 添加 senders(一个链表)。调用 signal 使用的 emit 其实什么都不是,可以直接调用该 signal 的函数也行,这会调用 QMetaObject::activate() 调用连接上的 slots。
No comments:
Post a Comment