继续探索connect方法

继续探索connect方法

又是忙碌的一天,终于在2224分的时候,可以坐下来,继续我的源码分析之路的。最近一段时间的分析,收获很大,每天都能学到非常多的新东西,很多都是之前见都没见过的内容。一定要坚持下去,大学毕业的时候,这会是一笔非常宝贵的财富。

言归正传,再次进入Connect函数:

在昨天的分析中,我们看到这个函数:

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;

}

当时没有仔细对该问题进行分析,QInternal_CallBackTable *cbt = global_callback_table();这一句中包含了很多的内容呢。

跟踪global_callback_table()函数,我们发现了如下的宏定义:

Q_GLOBAL_STATIC(QInternal_CallBackTable, global_callback_table)

#define Q_GLOBAL_STATIC(TYPE, NAME)      

#define Q_GLOBAL_STATIC_INIT(TYPE, NAME)                              /

    static QGlobalStatic<TYPE > this_##NAME = { Q_BASIC_ATOMIC_INITIALIZER(0), false }

 

#define Q_GLOBAL_STATIC(TYPE, NAME)                                     /

    Q_GLOBAL_STATIC_INIT(TYPE, NAME);                                   /

    static TYPE *NAME()                                                 /

    {                                                                   /

        if (!this_##NAME.pointer && !this_##NAME.destroyed) {           /

            TYPE *x = new TYPE;                                         /

            if (!this_##NAME.pointer.testAndSetOrdered(0, x))           /

                delete x;                                               /

            else                                                       /

                static QGlobalStaticDeleter<TYPE > cleanup(this_##NAME); /

        }                                                              /

        return this_##NAME.pointer;                                     /

    }

将这三个宏连接起来看,我们会得到如下代码:

typedef bool (*qInternalCallback)(void **);

struct QInternal_CallBackTable {

    QVector<QList<qInternalCallback> > callbacks;

};

// forward declaration, since qatomic.h needs qglobal.h

template <typename T> class QBasicAtomicPointer;//原子指针

// POD for Q_GLOBAL_STATIC

template <typename T>

class QGlobalStatic

{

public:

    QBasicAtomicPointer<T> pointer;

    bool destroyed;

};

Static QGlobalStatic<QInternal_CallBackTable> this_global_callback_table = { Q_BASIC_ATOMIC_INITIALIZER(0), false }//这里生成了函数指针的一个模板类,同时保证了线程安全。

static QInternal_CallBackTable * global_callback_table () 

{

        if (!this_global_callback_table.pointer &&

!this_ global_callback_table.pointer.destroyed) {

            QInternal_CallBackTable *x = new QInternal_CallBackTable;

            if (!this_global_callback_table.pointer.testAndSetOrdered(0, x))

                delete x;

            else

                static QGlobalStaticDeleter< QInternal_CallBackTable > cleanup this_global_callback_table);

        }                                                              

        Return  this_global_callback_table.pointer;

}

将宏定义转换为真正的编码后,我们看到,这里首先定义了全局的指针对象,随后创建了内部回调函数表对象的指针,最后返回。

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;

    }

首先查找了指定的回调函数,通过这个方法:cbt->callbacks[cb]cb在这里的值是:QInternal::ConnectCallback,但是目前想不到什么办法来查找这个回调函数的创建位置,进行了全局的搜索,调用QInternal::registerCallback该方法进行注册的地方只有一个,而且不是注册QInternal::ConnectCallback这个回调函数,所以不知道该如何查找下去了……

接下来的这个操作,循环执行了所有的回调函数,这些回调函数的指针是在调用registerCallback的时候创建出来的。

#ifndef QT_NO_DEBUG

    bool warnCompat = true;

#endif

    if (type == Qt::AutoCompatConnection) {

        type = Qt::AutoConnection;

#ifndef QT_NO_DEBUG

        warnCompat = false;

#endif

    }

这里针对调试环境做了一些设置,现在还不能理解其中的含义,继续往下看。

if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {

        qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",

                 sender ? sender->metaObject()->className() : "(null)",

                 (signal && *signal) ? signal+1 : "(null)",

                 receiver ? receiver->metaObject()->className() : "(null)",

                 (method && *method) ? method+1 : "(null)");

        return false;

    }

这里判断了信号的有效性,我们应该注意到,这里对这些参数判断之前,进入了连接的回调函数,也就是说,具体的判断应该是在ConnectCallback中进行的。

接下来是:

if (!check_signal_macro(sender, signal, "connect", "bind"))

        return false;

对这个函数进行跟踪,发现其作用是判断这个信号或者槽之前的标志(012)是否正确。

接下来是对信号函数的检索:

/*! /internal

    Same as QMetaObject::indexOfSignal, but the result is the local offset to the base object.

 

    /a baseObject will be adjusted to the enclosing QMetaObject, or 0 if the signal is not found

*/

int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject, const char *signal)

{

    int i = -1;

    while (*baseObject) {

        const QMetaObject *const m = *baseObject;

        for (i = priv(m->d.data)->methodCount-1; i >= 0; --i)

            if ((m->d.data[priv(m->d.data)->methodData + 5*i + 4] & MethodTypeMask) == MethodSignal

                && strcmp(signal, m->d.stringdata

                + m->d.data[priv(m->d.data)->methodData + 5*i]) == 0) {

                break;

            }

        if (i >= 0)

            break;

        *baseObject = m->d.superdata;

    }

#ifndef QT_NO_DEBUG

    const QMetaObject *m = *baseObject;

    if (i >= 0 && m && m->d.superdata) {

        int conflict = m->d.superdata->indexOfMethod(signal);

        if (conflict >= 0)

            qWarning("QMetaObject::indexOfSignal:%s: Conflict with %s::%s",

                     m->d.stringdata, m->d.superdata->d.stringdata, signal);

    }

#endif

    return i;

}

接下来的环节比较复杂,今天是分析不完了,时间不早了,也该去睡觉了,明天继续。

 

20091020日星期二 2344

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值