首先看看connect函数的原型,这个函数在QObject类别当中定义:
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType =Qt::AutoConnection);
由于这个函数是static类型,所以在整个程序当中仅有一个函数,也正因为这样保证了函数的入口唯一性。不过这个函数的调用与这个函数的原型不太一样。
connect(sender, SIGNAL(clicked()), receiver, SLOT(close()));
# define SLOT(a) qFlagLocation("1"#a QLOCATION) # define SIGNAL(a) qFlagLocation("2"#a QLOCATION)
注意这两个宏前面的字符串1和2,这里实际是为了区分signal和slot。
const int flagged_locations_count = 2; static const char* flagged_locations[flagged_locations_count] = {0}; const char *qFlagLocation(const char *method) { static int idx = 0; flagged_locations[idx] = method; idx = (idx+1) % flagged_locations_count; return method; }这里的idx每次累加1,正好将两个字符串放到不同的数组当中。而一个connect刚好同时存在一个signal和slot,这样的话每次connect调用之后都是的idx为0.完整的connect函数实现在qobject.cpp当中。在这个函数第一个调用是 QInternal ::activateCallbacks。
bool QInternal::activateCallbacks(Callback cb, void **parameters) { 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))(paratypedef bool (*qInternalCallback)(void **);
meters); return ret; } return false;} 看起来这里首先调用一个函数,实际这个函数式利用宏定义出来的。struct QInternal_CallBackTable { QVector<QList<qInternalCallback> > callbacks; }; Q_GLOBAL_STATIC(QInternal_CallBackTable, global_callback_table)#define Q_GLOBAL_STATIC(TYPE, NAME) \ static TYPE *NAME() \ { \ Q_GLOBAL_STATIC_INIT(TYPE, _StaticVar_); \ if (!this__StaticVar_.pointer && !this__StaticVar_.destroyed) { \ TYPE *x = new TYPE; \ if (!this__StaticVar_.pointer.testAndSetOrdered(0, x)) \ delete x; \ else \ static QGlobalStaticDeleter<TYPE > cleanup(this__StaticVar_); \ } \ return this__StaticVar_.pointer; \ }#define Q_GLOBAL_STATIC_INIT(TYPE, NAME) \ static QGlobalStatic<TYPE > this_ ## NAME \ = { Q_BASIC_ATOMIC_INITIALIZER(0), false }整个宏展开就是为了返回一个指针,由于最后的QGlobalStatic是一个全局的静态变量。所以这个宏并不是什么都没做,而是对这个全局指针进行检查,如果这个指针不存在,那么就将他给new出来,同时设置出师化值为0,如果初始化不成功,直接delete掉,反之为这个全局变量定义一个清理类别。因为析构函数和构造函数调用的顺序刚好相反,所以这里刚好先将指针给清理掉,然后再调用QGlobalStatic的析构函数。typedef bool (*qInternalCallback)(void **);这些回调函数在系统刚刚初始化的时候被设置。回调函数的原型如上面所示。到这里整个函数的流程很明了了,只不过借助了List和Vector的管理。整个函数在qglobal.cpp当中实现。回到connect函数,接下来是对参数进行检查,当参数有问题就打印调试错误。
static bool check_signal_macro(const QObject *sender, const char *signal, const char *func, const char *op) { int sigcode = extract_code(signal); if (sigcode != QSIGNAL_CODE) { if (sigcode == QSLOT_CODE) qWarning("Object::%s: Attempt to %s non-signal %s::%s", func, op, sender->metaObject()->className(), signal+1); else qWarning("Object::%s: Use the SIGNAL macro to %s %s::%s", func, op, sender->metaObject()->className(), signal); return false; } return true; } static int extract_code(const char *member) { return (((int)(*member) - '0') & 0x3); } 首先减掉字符0的以得到数值,然后和0x03相与分理出数值1或者2;而这个正好是在宏里面添加的前缀标识符。函数里面的两个宏名称也不言而喻了,很明显,一个是数值1,另一个而是数值2.由于不能多个信号对应一个槽,所以这里要检测是否存在这种情况。
int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,const char *signal,bool normalizeStringData) { int i = indexOfMethodRelative<MethodSignal>(baseObject, signal, normalizeStringData); 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); } return i; } 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; } static inline const QMetaObjectPrivate *priv(const uint* data) { return reinterpret_cast<const QMetaObjectPrivate*>(data); }