QT实现(2)

6 篇文章 0 订阅

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













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值