首先看看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); }