读QT5.7源码(四)QMetaMethod 和 QMetaMethodPrivate

        QMetaMethod   和 QMetaMethodPrivate  是用来管理QMetaObject包含信息中的函数节的。MOC生成的函数结构图如下


首先是字符串结构








函数结构图:





每个函数节 占5个int   ,第一个是函数名字符串,在字符串数组中的索引值为3,刚好对应字符数组中的“TestSignal3”,第三个是其参数段的偏移量41刚好是,第一个参数节






参数节的构成图:








QMetaMethod   和 QMetaMethodPrivate 的定义



class Q_CORE_EXPORT QMetaMethod
{
public:
    Q_DECL_CONSTEXPR inline QMetaMethod() : mobj(Q_NULLPTR), handle(0) {}

    QByteArray methodSignature() const;
    QByteArray name() const;
    const char *typeName() const;
    int returnType() const;
    int parameterCount() const;
    int parameterType(int index) const;
    void getParameterTypes(int *types) const;
    QList<QByteArray> parameterTypes() const;
    QList<QByteArray> parameterNames() const;
    const char *tag() const;
    enum Access { Private, Protected, Public };
    Access access() const;
    enum MethodType { Method, Signal, Slot, Constructor };
    MethodType methodType() const;
    enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 };
    int attributes() const;
    int methodIndex() const;
    int revision() const;

    inline const QMetaObject *enclosingMetaObject() const { return mobj; }


   ............................................................省略
    inline bool isValid() const { return mobj != Q_NULLPTR; }

#ifdef Q_QDOC
    static QMetaMethod fromSignal(PointerToMemberFunction signal);
#else
    template <typename Func>
    static inline QMetaMethod fromSignal(Func signal)
    {
        typedef QtPrivate::FunctionPointer<Func> SignalType;
        Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
                          "No Q_OBJECT in the class with the signal");
        return fromSignalImpl(&SignalType::Object::staticMetaObject,
                              reinterpret_cast<void **>(&signal));
    }
#endif

private:

    static QMetaMethod fromSignalImpl(const QMetaObject *, void **);

    const QMetaObject *mobj;
    uint handle;
    friend class QMetaMethodPrivate;
    friend struct QMetaObject;
    friend struct QMetaObjectPrivate;
    friend class QObject;
    friend bool operator==(const QMetaMethod &m1, const QMetaMethod &m2);
    friend bool operator!=(const QMetaMethod &m1, const QMetaMethod &m2);
};


class QMetaMethodPrivate : public QMetaMethod
{
public:
    static const QMetaMethodPrivate *get(const QMetaMethod *q)
    { return static_cast<const QMetaMethodPrivate *>(q); }

    inline QByteArray signature() const;
    inline QByteArray name() const;
    inline int typesDataIndex() const;
    inline const char *rawReturnTypeName() const;
    inline int returnType() const;
    inline int parameterCount() const;
    inline int parametersDataIndex() const;
    inline uint parameterTypeInfo(int index) const;
    inline int parameterType(int index) const;
    inline void getParameterTypes(int *types) const;
    inline QList<QByteArray> parameterTypes() const;
    inline QList<QByteArray> parameterNames() const;
    inline QByteArray tag() const;
    inline int ownMethodIndex() const;

private:
    QMetaMethodPrivate();
}

两个数据成员 mobj  QMetaObject类的指针, handle 函数节的偏移量,  所有的方法都围绕这两个成员展开



QMetaMethodPrivate 的构造函数是私有的 只能通过 static const QMetaMethodPrivate *get(const QMetaMethod *q)  静态函数  将QMetaMethod 对象指针转换为

QMetaMethodPrivate指针来使用该类的函数



1、QByteArray    QMetaMethodPrivate::name() ;    返回   QByteArray标识了函数的名称

QByteArray QMetaMethodPrivate::name() const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    return stringData(mobj, mobj->d.data[handle]);  传函数节的第一个int给Index
}


static inline const QByteArray stringData(const QMetaObject *mo, int index)
{
    Q_ASSERT(priv(mo->d.data)->revision >= 7);  版本检查
    const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) };   节的第一个int值为函数名在stringdata中的索引
    Q_ASSERT(data.ptr->ref.isStatic());
    Q_ASSERT(data.ptr->alloc == 0);
    Q_ASSERT(data.ptr->capacityReserved == 0);
    Q_ASSERT(data.ptr->size >= 0);
    return data;                                         这里用节数据直接构成QbyteArray对象,不做深拷贝,
}

2、int QMetaMethodPrivate:: parameterCount ()    返回函数的参数个数
int QMetaMethodPrivate::parameterCount() const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    return mobj->d.data[handle + 1];     函数节的第二个int标识了参数个数
}


3、int QMetaMethodPrivate::typesDataIndex() const     返回参数节的偏移量

int QMetaMethodPrivate::typesDataIndex() const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    return mobj->d.data[handle + 2];   函数节的第三个int标识了参数节的偏移量
}


4、int QMetaMethodPrivate::parametersDataIndex() const   返回参数节中 参数块的偏移

int QMetaMethodPrivate::parametersDataIndex() const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    return typesDataIndex() + 1;    参数节偏移+1   参数节第一个int是返回值因此+1
}


5、const char *QMetaMethodPrivate::r awReturnTypeName () const  返回函数返回值类型的字符串

const char *QMetaMethodPrivate::rawReturnTypeName() const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    uint typeInfo = mobj->d.data[typesDataIndex()];    参数节的第一个int  返回值
    if (typeInfo & IsUnresolvedType)                // IsUnresolvedType = 0x80000000 未解决的类型
        return rawStringData(mobj, typeInfo & TypeNameIndexMask);
    else
        return QMetaType::typeName(typeInfo);   如果是QMetaType内建的用typeName 转换
}


6、uint QMetaMethodPrivate::
parameterTypeInfo(int index) const       返回第index个参数的int值    index=-1时是返回值

uint QMetaMethodPrivate::parameterTypeInfo(int index) const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    return mobj->d.data[parametersDataIndex() + index];  节首地址+Index
}


7、int QMetaMethodPrivate:: parameterType (int index) const       返回第index个参数的 QMetaType值

int QMetaMethodPrivate::parameterType(int index) const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    return typeFromTypeInfo(mobj, parameterTypeInfo(index));
}

static inline int typeFromTypeInfo(const QMetaObject *mo, uint typeInfo)
{
    if (!(typeInfo & IsUnresolvedType))
        return typeInfo;
    return QMetaType::type(stringData(mo, typeInfo & TypeNameIndexMask));
}

8、int QMetaMethodPrivate:: returnType() const   返回  函数返回值的QMetaType值

int QMetaMethodPrivate::returnType() const
{
    return parameterType(-1);
}


9、void QMetaMethodPrivate::getParameterTypes(int *types) const      传递一个字节数组  用函数每一个参数的QMetaType值 填充这个数组


void QMetaMethodPrivate::getParameterTypes(int *types) const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    int dataIndex = parametersDataIndex();  函数参数节偏移
    int argc = parameterCount();            参数个数
    for (int i = 0; i < argc; ++i) {
        int id = typeFromTypeInfo(mobj, mobj->d.data[dataIndex++]);   获取每一个参数的QMetaType值
        *(types++) = id;
    }
}

10、QList<QByteArray> QMetaMethodPrivate::
parameterTypes() const     将函数类型名字符串 加入到QList<QByteArray>链表中
QList<QByteArray> QMetaMethodPrivate::parameterTypes() const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    int argc = parameterCount();
    QList<QByteArray> list;
    list.reserve(argc);
    int paramsIndex = parametersDataIndex();
    for (int i = 0; i < argc; ++i)
        list += typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + i]);
    return list;
}

11、QList<QByteArray> QMetaMethodPrivate::parameterNames()const    获取参数的形参名  放入链表     形参名的索引放在参数节首地址+参数个数

QList<QByteArray> QMetaMethodPrivate::parameterNames() const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    int argc = parameterCount();
    QList<QByteArray> list;
    list.reserve(argc);
    int namesIndex = parametersDataIndex() + argc;
    for (int i = 0; i < argc; ++i)
        list += stringData(mobj, mobj->d.data[namesIndex + i]);  //stringData根据索引在字符串Block中找到对应的QByteArray
    return list;
}


12、QByteArray QMetaMethodPrivate::tag() const     获取函数节的标签值   标签值位于节的第4个int

QByteArray QMetaMethodPrivate::tag() const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    return stringData(mobj, mobj->d.data[handle + 3]);
}


13、QByteArray QMetaMethodPrivate::signature() const    获取函数名字符串  参数类型名字符串链表   然后合成 一个信号用的函数字符串  不带参数名 只有类型名


QByteArray QMetaMethodPrivate::signature() const
{
    Q_ASSERT(priv(mobj->d.data)->revision >= 7);
    QByteArray result;
    result.reserve(256);
    result += name();    获取函数名字符串
    result += '(';
    QList<QByteArray> argTypes = parameterTypes();  获取参数字符串
    for (int i = 0; i < argTypes.size(); ++i) {
        if (i)
            result += ',';
        result += argTypes.at(i);
    }
    result += ')';
    return result;
}





14、QMetaMethod  的很多函数  中转调用了QMetaMethodPrivate的内联函数来实现其功能,因为父类和子类的对象模型是一样的。

QByteArray QMetaMethod::methodSignature() const
{
    if (!mobj)
        return QByteArray();
    return QMetaMethodPrivate::get(this)->signature();
}

QByteArray QMetaMethod::name() const
{
    if (!mobj)
        return QByteArray();
    return QMetaMethodPrivate::get(this)->name();
}


int QMetaMethod::returnType() const
 {
     if (!mobj)
         return QMetaType::UnknownType;
    return QMetaMethodPrivate::get(this)->returnType();
}


int QMetaMethod::parameterCount() const
{
    if (!mobj)
        return 0;
    return QMetaMethodPrivate::get(this)->parameterCount();
}


int QMetaMethod::parameterType(int index) const
{
    if (!mobj || index < 0)
        return QMetaType::UnknownType;
    if (index >= QMetaMethodPrivate::get(this)->parameterCount())
        return QMetaType::UnknownType;

    int type = QMetaMethodPrivate::get(this)->parameterType(index);
    if (type != QMetaType::UnknownType)
        return type;

    void *argv[] = { &type, &index };
    mobj->static_metacall(QMetaObject::RegisterMethodArgumentMetaType, QMetaMethodPrivate::get(this)->ownMethodIndex(), argv);
    if (type != -1)
        return type;
    return QMetaType::UnknownType;
}


void QMetaMethod::getParameterTypes(int *types) const
{
    if (!mobj)
        return;
    QMetaMethodPrivate::get(this)->getParameterTypes(types);
}


QList<QByteArray> QMetaMethod::parameterTypes() const
{
    if (!mobj)
        return QList<QByteArray>();
    return QMetaMethodPrivate::get(this)->parameterTypes();
}


QList<QByteArray> QMetaMethod::parameterNames() const
{
    QList<QByteArray> list;
    if (!mobj)
        return list;
    return QMetaMethodPrivate::get(this)->parameterNames();
}



const char *QMetaMethod::typeName() const
{
    if (!mobj)
        return 0;
    return QMetaMethodPrivate::get(this)->rawReturnTypeName();
}


const char *QMetaMethod::tag() const
{
    if (!mobj)
        return 0;
    return QMetaMethodPrivate::get(this)->tag().constData();
}


15、QMetaMethod 特有的方法:


int QMetaMethod::attributes() const
{
    if (!mobj)
        return false;
    return ((mobj->d.data[handle + 4])>>4);
}
  返回函数的类型 


int QMetaMethod::methodIndex() const
{
    if (!mobj)
        return -1;
    return QMetaMethodPrivate::get(this)->ownMethodIndex() + mobj->methodOffset();
}

返回继承+自由函数组中的索引


QMetaMethod::Access QMetaMethod::access() const
{
    if (!mobj)
        return Private;
    return (QMetaMethod::Access)(mobj->d.data[handle + 4] & AccessMask);
}

返回函数的访问权限   enum Access { Private, Protected, Public };     flags&AccessMask    

enum MethodFlags  {
    AccessPrivate = 0x00,
    AccessProtected = 0x01,
    AccessPublic = 0x02,
    AccessMask = 0x03, //mask


    MethodMethod = 0x00,
    MethodSignal = 0x04,
    MethodSlot = 0x08,
    MethodConstructor = 0x0c,
    MethodTypeMask = 0x0c,


    MethodCompatibility = 0x10,
    MethodCloned = 0x20,
    MethodScriptable = 0x40,
    MethodRevisioned = 0x80
};


QMetaMethod::MethodType QMetaMethod::methodType() const
{
    if (!mobj)
        return QMetaMethod::Method;
    return (QMetaMethod::MethodType)((mobj->d.data[handle + 4] & MethodTypeMask)>>2);
}

返回  函数的类型 信号  槽或其他类型



16、QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **signal)   根据信号函数的指针 返回一个QMetaMethod


MOC生成的static_metacall 示例

void Widget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        Widget *_t = static_cast<Widget *>(_o);
        Q_UNUSED(_t)
        switch (_id) {
        case 0: _t->TestSignal1((*reinterpret_cast< QString(*)>(_a[1]))); break;
        case 1: _t->TestSignal2((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
        case 2: _t->TestSignal3(); break;
        case 3: _t->TestSlot((*reinterpret_cast< QString(*)>(_a[1]))); break;
        case 4: _t->MethodTest((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
        default: ;
        }
    } else if (_c == QMetaObject::IndexOfMethod) {  // 如果是查询函数索引
        int *result = reinterpret_cast<int *>(_a[0]);     _a[0]存放查询结果
        void **func = reinterpret_cast<void **>(_a[1]);   -a[1]是要查询的函数的内存地址
1        {
            typedef void (Widget::*_t)(QString & );
            if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&Widget::TestSignal1)) {      如果地址匹配
                *result = 0;                               将索引放入_a[0]
                return;
            }
        }
        {
            typedef void (Widget::*_t)(QString & , int );
            if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&Widget::TestSignal2)) {
                *result = 1;
                return;
            }
        }
        {
            typedef void (Widget::*_t)();
            if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&Widget::TestSignal3)) {
                *result = 2;
                return;
            }
        }
    }



QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **signal)
{
    int i = -1;
    void *args[] = { &i, signal };   i来返回查询结果   *signal 信号函数内存地址
    QMetaMethod result;
    for (const QMetaObject *m = metaObject; m; m = m->d.superdata) {
        m->static_metacall(QMetaObject::IndexOfMethod, 0, args);    参见下面的QMetaObject::static_metacall
        if (i >= 0) {
            result.mobj = m;                                        如果返回了索引 
            result.handle = priv(m->d.data)->methodData + 5*i;      用索引定位Handle  构建QmetaMethod
            break;
        }
    }
    return result;
}

int QMetaObject::static_metacall(Call cl, int idx, void **argv) const
{
    Q_ASSERT(priv(d.data)->revision >= 6);
    if (!d.static_metacall)
        return 0;
    d.static_metacall(0, cl, idx, argv);
    return -1;
}




17、bool QMetaMethod::invoke  调用该函数


bool QMetaMethod::invoke(QObject *object,
                         Qt::ConnectionType connectionType,
                         QGenericReturnArgument returnValue,
                         QGenericArgument val0,
                         QGenericArgument val1,
                         QGenericArgument val2,
                         QGenericArgument val3,
                         QGenericArgument val4,
                         QGenericArgument val5,
                         QGenericArgument val6,
                         QGenericArgument val7,
                         QGenericArgument val8,
                         QGenericArgument val9) const
{
    if (!object || !mobj)
        return false;

    Q_ASSERT(mobj->cast(object));

    // check return type
    if (returnValue.data()) {
        const char *retType = typeName();
        if (qstrcmp(returnValue.name(), retType) != 0) {
            // normalize the return value as well
            QByteArray normalized = QMetaObject::normalizedType(returnValue.name());
            if (qstrcmp(normalized.constData(), retType) != 0) {
                // String comparison failed, try compare the metatype.
                int t = returnType();
                if (t == QMetaType::UnknownType || t != QMetaType::type(normalized))
                    return false;
            }
        }
    }                                                          //判断返回值类型是否匹配

    // check argument count (we don't allow invoking a method if given too few arguments)
    const char *typeNames[] = {
        returnValue.name(),
        val0.name(),
        val1.name(),
        val2.name(),
        val3.name(),
        val4.name(),
        val5.name(),
        val6.name(),
        val7.name(),
        val8.name(),
        val9.name()
    };                                 //参数类型字符串数组
    int paramCount;
    for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
        if (qstrlen(typeNames[paramCount]) <= 0)
            break;                     //实际传过来的可用参数个数
    }
    if (paramCount <= QMetaMethodPrivate::get(this)->parameterCount())     如果传过来的参数小于函数所需参数 返回失败
        return false;

    // check connection type
    QThread *currentThread = QThread::currentThread();
    QThread *objectThread = object->thread();
    if (connectionType == Qt::AutoConnection) {
        connectionType = currentThread == objectThread
                         ? Qt::DirectConnection
                         : Qt::QueuedConnection;                      设置链接类型。如果为AutoConnection,则判断调用线程和对象所处线程是不是同一个
    }                                                                 是的话设置为直接调用,不是的话设置为队列调用

#ifdef QT_NO_THREAD
    if (connectionType == Qt::BlockingQueuedConnection) {
        connectionType = Qt::DirectConnection;
    }
#endif

    // invoke!
    void *param[] = {
        returnValue.data(),
        val0.data(),
        val1.data(),
        val2.data(),
        val3.data(),
        val4.data(),
        val5.data(),
        val6.data(),
        val7.data(),
        val8.data(),
        val9.data()
    };  参数值数组
    int idx_relative = QMetaMethodPrivate::get(this)->ownMethodIndex();    相对于自身索引
    int idx_offset =  mobj->methodOffset();     //想对于继承过来的函数的偏移
    Q_ASSERT(QMetaObjectPrivate::get(mobj)->revision >= 6);
    QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall;

    if (connectionType == Qt::DirectConnection) {
        if (callFunction) {
            callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param);
            return true;
        } else {
            return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, idx_relative + idx_offset, param) < 0;     调用静态metacall或者动态call
        }
    } else if (connectionType == Qt::QueuedConnection) {
        if (returnValue.data()) {
            qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
                     "queued connections");
            return false;
        }                                             如果是队列方式,不能有返回值

        int nargs = 1; // include return type
        void **args = (void **) malloc(paramCount * sizeof(void *));
        Q_CHECK_PTR(args);
        int *types = (int *) malloc(paramCount * sizeof(int));
        Q_CHECK_PTR(types);
        types[0] = 0; // return type
        args[0] = 0;

        for (int i = 1; i < paramCount; ++i) {
            types[i] = QMetaType::type(typeNames[i]);
            if (types[i] != QMetaType::UnknownType) {
                args[i] = QMetaType::create(types[i], param[i]);
                ++nargs;
            } else if (param[i]) {
                // Try to register the type and try again before reporting an error.
                void *argv[] = { &types[i], &i };
                QMetaObject::metacall(object, QMetaObject::RegisterMethodArgumentMetaType,
                                      idx_relative + idx_offset, argv);
                if (types[i] == -1) {
                    qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'",
                            typeNames[i]);
                    for (int x = 1; x < i; ++x) {
                        if (types[x] && args[x])
                            QMetaType::destroy(types[x], args[x]);
                    }
                    free(types);
                    free(args);
                    return false;
                }
            }
        }   复制参数
                         加入事件队列
        QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
                                                        0, -1, nargs, types, args));
    } else { // blocking queued connection
#ifndef QT_NO_THREAD
        if (currentThread == objectThread) {
            qWarning("QMetaMethod::invoke: Dead lock detected in "
                        "BlockingQueuedConnection: Receiver is %s(%p)",
                        mobj->className(), object);
        }

        QSemaphore semaphore;
        QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
                                                        0, -1, 0, 0, param, &semaphore));
        semaphore.acquire();
#endif // QT_NO_THREAD
    }
    return true;
}







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值