QT实现(4)

6 篇文章 0 订阅
       err_method_notfound(sender, signal_arg, "connect");
       err_info_about_objects("connect", sender, receiver);
在上面的处理之后,如果不能得到正确的序号,那么编译器就通过上面的函数输出编译信息,提示connec不正确。
int QMetaObjectPrivate::originalClone(const QMetaObject *mobj, int local_method_index)
{
   int handle = get(mobj)->methodData + 5 * local_method_index;
   while (mobj->d.data[handle + 4] & MethodCloned) {
       handle -= 5;
       local_method_index--;
   }
   return local_method_index;
}

每一个信号和槽函数的相关信息包含五个数字,所以这里的索引值是基位置加上5*索引值,其中以handle为基地址的第四个表示函数的一些属性。这里如果函数的属性是MethodClone则将这个索引减掉。有关信息可以参考QT实现(1)以及qmeta_p.h的相关定义。

static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset)
{
    *signalOffset = *methodOffset = 0;
    const QMetaObject *m = metaobject->d.superdata;
    while (m) {
        const QMetaObjectPrivate *d = QMetaObjectPrivate::get(m);
        *methodOffset += d->methodCount;
        *signalOffset += (d->revision >= 4) ? d->signalCount : d->methodCount;
        m = m->d.superdata;
    }
}
将所有的信号和槽的偏移累加起来,由于在revision<4的时候,method技术和信号计数是同一个,所以才会有这样的格式。同样的,槽函数的计数实际可以通过method的计数减去信号的计数。由于这里是递加自身以及自身父类的信号和槽的函数技术,所以在QT实现一当中一次递减的是本身所在类的全部的索引。
int signal_absolute_index = signal_index + methodOffset;
    signal_index += signalOffset;

    QByteArray tmp_method_name;
    int membcode = extract_code(method);
int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
                                    const char *slot,
                                    bool normalizeStringData)
{
    return indexOfMethodRelative<MethodSlot>(m, slot, normalizeStringData);
}
这里又转到上面的函数当中,主要还是用于获取索引值。
QMetaMethod smethod = smeta->method(signal_absolute_index);
QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());

上面的函数用于创建QMetaMethod类别,QMetaMethod定义在qmetaobject.h当中

QMetaMethod QMetaObject::method(int index) const

{

   int i = index;

   i -= methodOffset();

   if (i < 0 && d.superdata)

       return d.superdata->method(index);

   QMetaMethod result;

   if (i >= 0 && i < priv(d.data)->methodCount) {

       result.mobj = this;

       result.handle = priv(d.data)->methodData + 5*i;

   }

   return result;

}

bool QMetaObjectPrivate ::connect ( const QObject * sender , int signal_index ,
                                 const QObject *receiver, int method_index,
                                 const QMetaObject *rmeta, int type, int *types)
{
    QObject *s = const_cast<QObject *>(sender);
    QObject *r = const_cast<QObject *>(receiver);
    int method_offset = rmeta ? rmeta->methodOffset() : 0;
    QObjectPrivate::StaticMetaCallFunction callFunction =
        (rmeta && QMetaObjectPrivate::get(rmeta)->revision >= 6 && rmeta->d.extradata)
        ? reinterpret_cast<const QMetaObjectExtraData *>(rmeta->d.extradata)->static_metacall : 0;
    QOrderedMutexLocker locker(signalSlotLock(sender),
                               signalSlotLock(receiver));
    if (type & Qt::UniqueConnection) {
        QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
        if (connectionLists && connectionLists->count() > signal_index) {
            const QObjectPrivate::Connection *c2 =
                (*connectionLists)[signal_index].first;
            int method_index_absolute = method_index + method_offset;
            while (c2) {
                if (c2->receiver == receiver && c2->method() == method_index_absolute)
                    return false;
                c2 = c2->nextConnectionList;
            }
        }
        type &= Qt::UniqueConnection - 1;
    }
    QObjectPrivate::Connection *c = new QObjectPrivate::Connection;
    c->sender = s;
    c->receiver = r;
    c->method_relative = method_index;
    c->method_offset = method_offset;
    c->connectionType = type;
    c->argumentTypes = types;
    c->nextConnectionList = 0;
    c->callFunction = callFunction;
    QT_TRY {
        QObjectPrivate::get(s)->addConnection(signal_index, c);
    } QT_CATCH(...) {
        delete c;
        QT_RETHROW;
    }
    c->prev = &(QObjectPrivate::get(r)->senders);
    c->next = *c->prev;
    *c->prev = c;
    if (c->next)
        c->next->prev = &c->next;
    QObjectPrivate *const sender_d = QObjectPrivate::get(s);
    if (signal_index < 0) {
        sender_d->connectedSignals[0] = sender_d->connectedSignals[1] = ~0;
    } else if (signal_index < (int)sizeof(sender_d->connectedSignals) * 8) {
        sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f));
    }
    return true;
}

整个connect过程分为四步,第一步根据类型是否是unique检验connect是否是唯一的连接。如果之前已经有连接,那么直接返回false,否则继续。第二步,在当前是unique的情况下之前没有connect或者没有unique要求的时候直接创建connection类别。第三步调用addConnection将刚刚创建的connection加入到链表当中。第四步,设置信号的位图。看起来很复杂的prev和next,实际这里只是单链表的挂在,最后的senders值为C,然后利用八位的位图置信号位。之余Lock是为了在函数跳出的时候自动析构,从而避免使用者忘记解锁。

void QObjectPrivate::addConnection(int signal, Connection *c)

{

   if (!connectionLists)

       connectionLists = new QObjectConnectionListVector();

   if (signal >= connectionLists->count())

       connectionLists->resize(signal + 1);

   ConnectionList &connectionList = (*connectionLists)[signal];

   if (connectionList.last) {

       connectionList.last->nextConnectionList = c;

   } else {

       connectionList.first = c;

   }

   connectionList.last = c;

   cleanConnectionLists();

}

利用尾插法将建立connection链表。然后根据需要清除无效的链表项目,因为QT是可以disconnect的。

void QObjectPrivate::cleanConnectionLists()

{

   if (connectionLists->dirty && !connectionLists->inUse) {

       for (int signal = -1; signal < connectionLists->count(); ++signal) {

           QObjectPrivate::ConnectionList &connectionList =

               (*connectionLists)[signal];

           QObjectPrivate::Connection *last = 0;

           QObjectPrivate::Connection **prev = &connectionList.first;

           QObjectPrivate::Connection *c = *prev;

           while (c) {

               if (c->receiver) {

                   last = c;

                   prev = &c->nextConnectionList;

                   c = *prev;

               } else {

                   QObjectPrivate::Connection *next = c->nextConnectionList;

                   *prev = next;

                   delete c;

                   c = next;

               }

           }

           connectionList.last = last;

       }

       connectionLists->dirty = false;

   }

}

下面列出整个connect函数的实现。通过之前的分析,可以看出整个函数分为三部分,参数验证和相应的参数转化,然后才是真正的实现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;

   }

   if (type == Qt::AutoCompatConnection) {

       type = Qt::AutoConnection;

   }

   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;

   }

   QByteArray tmp_signal_name;

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

       return false;

   const QMetaObject *smeta = sender->metaObject();

   const char *signal_arg = signal;

   ++signal; //skip code

   int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);

   if (signal_index < 0) {

       // check for normalized signatures

       tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);

       signal = tmp_signal_name.constData() + 1;

       smeta = sender->metaObject();

       signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);

   }

   if (signal_index < 0) {

       // re-use tmp_signal_name and signal from above

       smeta = sender->metaObject();

       signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);

   }

   if (signal_index < 0) {

       err_method_notfound(sender, signal_arg, "connect");

       err_info_about_objects("connect", sender, receiver);

       return false;

   }

   signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);

   int signalOffset, methodOffset;

   computeOffsets(smeta, &signalOffset, &methodOffset);

   int signal_absolute_index = signal_index + methodOffset;

   signal_index += signalOffset;

   QByteArray tmp_method_name;

   int membcode = extract_code(method);

   if (!check_method_code(membcode, receiver, method, "connect"))

       return false;

   const char *method_arg = method;

   ++method; // skip code

   const QMetaObject *rmeta = receiver->metaObject();

   int method_index_relative = -1;

   switch (membcode) {

   case QSLOT_CODE:

       method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);

       break;

   case QSIGNAL_CODE:

       method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);

       break;

   }

   if (method_index_relative < 0) {

       // check for normalized methods

       tmp_method_name = QMetaObject::normalizedSignature(method);

       method = tmp_method_name.constData();

       // rmeta may have been modified above

       rmeta = receiver->metaObject();

       switch (membcode) {

       case QSLOT_CODE:

           method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);

           if (method_index_relative < 0)

               method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true);

           break;

       case QSIGNAL_CODE:

           method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);

           if (method_index_relative < 0)

               method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true);

           break;

       }

   }

   if (method_index_relative < 0) {

       err_method_notfound(receiver, method_arg, "connect");

       err_info_about_objects("connect", sender, receiver);

       return false;

   }

   if (!QMetaObject::checkConnectArgs(signal, method)) {

       qWarning("QObject::connect: Incompatible sender/receiver arguments"

                "\n        %s::%s --> %s::%s",

                sender->metaObject()->className(), signal,

                receiver->metaObject()->className(), method);

       return false;

   }

   int *types = 0;

   if ((type == Qt::QueuedConnection)

           && !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes())))

       return false;

   if (warnCompat) {

       QMetaMethod smethod = smeta->method(signal_absolute_index);

       QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());

       check_and_warn_compat(smeta, smethod, rmeta, rmethod);

   }

   if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index_relative, rmeta ,type, types))

       return false;

   const_cast<QObject*>(sender)->connectNotify(signal - 1);

   return true;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值