读QT5.7源码(七)QMetaObjectPrivate

QMetaObjectPrivate  提供了对QMetaObject类成员中 uint类型数组的管理,这是个复杂的结构,因此QMetaObjectPrivate提供了结构的定义和操作函数,来方便对其的管理工作。



添加了  classInfo method emum property 后MOC生成的 QMetaObject.data 节


类的声明:

class Widget : public QWidget
{
    Q_OBJECT
    //Q_DECLARE_PRIVATE(Widget)
public:

    Q_CLASSINFO("WidgetInfo", "InfoTest")
    Q_PROPERTY(QString prop1 READ prop1)
    enum SelectionBehavior {
        SelectItems,
        SelectRows,
        SelectColumns
    };
    Q_ENUM(SelectionBehavior)
    Q_FLAGS(SelectionBehavior)

    Q_INVOKABLE void MethodTest(QString &,int);
public:
    Widget(QWidget *parent = 0);
    ~Widget();
protected slots:
    void TestSlot(QString &str);
signals:
    void TestSignal1(QString &str);
    void TestSignal2(QString &str,int i);
    void TestSignal3();
};




对应的MOC生成的两个数组  


static const qt_meta_stringdata_Widget_t qt_meta_stringdata_Widget = {
    {
QT_MOC_LITERAL(0, 0, 6), // "Widget"
QT_MOC_LITERAL(1, 7, 10), // "WidgetInfo"
QT_MOC_LITERAL(2, 18, 8), // "InfoTest"
QT_MOC_LITERAL(3, 27, 11), // "TestSignal1"
QT_MOC_LITERAL(4, 39, 0), // ""
QT_MOC_LITERAL(5, 40, 8), // "QString&"
QT_MOC_LITERAL(6, 49, 3), // "str"
QT_MOC_LITERAL(7, 53, 11), // "TestSignal2"
QT_MOC_LITERAL(8, 65, 1), // "i"
QT_MOC_LITERAL(9, 67, 11), // "TestSignal3"
QT_MOC_LITERAL(10, 79, 8), // "TestSlot"
QT_MOC_LITERAL(11, 88, 10), // "MethodTest"
QT_MOC_LITERAL(12, 99, 5), // "prop1"
QT_MOC_LITERAL(13, 105, 17), // "SelectionBehavior"
QT_MOC_LITERAL(14, 123, 11), // "SelectItems"
QT_MOC_LITERAL(15, 135, 10), // "SelectRows"
QT_MOC_LITERAL(16, 146, 13) // "SelectColumns"

    },
    "Widget\0WidgetInfo\0InfoTest\0TestSignal1\0"
    "\0QString&\0str\0TestSignal2\0i\0TestSignal3\0"
    "TestSlot\0MethodTest\0prop1\0SelectionBehavior\0"
    "SelectItems\0SelectRows\0SelectColumns"
};
#undef QT_MOC_LITERAL

static const uint qt_meta_data_Widget[] = {

 // content:
       7,       // revision
       0,       // classname
       1,   14, // classinfo
       5,   16, // methods
       1,   58, // properties
       1,   61, // enums/sets
       0,    0, // constructors
       0,       // flags
       3,       // signalCount

 // classinfo: key, value
       1,    2,

 // signals: name, argc, parameters, tag, flags
       3,    1,   41,    4, 0x06 /* Public */,
       7,    2,   44,    4, 0x06 /* Public */,
       9,    0,   49,    4, 0x06 /* Public */,

 // slots: name, argc, parameters, tag, flags
      10,    1,   50,    4, 0x09 /* Protected */,

 // methods: name, argc, parameters, tag, flags
      11,    2,   53,    4, 0x02 /* Public */,

 // signals: parameters
    QMetaType::Void, 0x80000000 | 5,    6,
    QMetaType::Void, 0x80000000 | 5, QMetaType::Int,    6,    8,
    QMetaType::Void,

 // slots: parameters
    QMetaType::Void, 0x80000000 | 5,    6,

 // methods: parameters
    QMetaType::Void, 0x80000000 | 5, QMetaType::Int,    4,    4,

 // properties: name, type, flags
      12, QMetaType::QString, 0x00095001,

 // enums: name, flags, count, data
      13, 0x1,    3,   65,

 // enum data: key, value
      14, uint(Widget::SelectItems),
      15, uint(Widget::SelectRows),
      16, uint(Widget::SelectColumns),

       0        // eod
};



       1,   14, // classinfo
       5,   16, // methods
       1,   58, // properties
       1,   61, // enums/sets


前面是数量,后面是数据的相对偏移量。

QMetaObjectPrivate 类定义:

struct QMetaObjectPrivate
{
    enum { OutputRevision = 7 }; // Used by moc, qmetaobjectbuilder and qdbus

    int revision;  版本号
    int className;    类名称索引
    int classInfoCount, classInfoData;   classInfo的数量,及索引 ,需要有宏定义才会被MOC生成
    int methodCount, methodData;         函数数量及索引,需要有宏定义才会被MOC生成
    int propertyCount, propertyData;          property数量及索引,需要有宏定义才会被MOC生成

    int enumeratorCount, enumeratorData;       枚举成员数量及索引,需要有宏定义才会被MOC生成
    int constructorCount, constructorData; //since revision 2    构造函数数量及索引,需要有宏定义才会被MOC生成
    int flags; //since revision 3                flags的数量
    int signalCount; //since revision 4      信号数量


    static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
    { return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }     将QMetaObject的data指向的内存结构转为QMetaObjectPrivate的指针,来管理

    static int originalClone(const QMetaObject *obj, int local_method_index);

    static QByteArray decodeMethodSignature(const char *signature,
                                            QArgumentTypeArray &types);
    static int indexOfSignalRelative(const QMetaObject **baseObject,
                                     const QByteArray &name, int argc,
                                     const QArgumentType *types);
    static int indexOfSlotRelative(const QMetaObject **m,
                                   const QByteArray &name, int argc,
                                   const QArgumentType *types);
    static int indexOfSignal(const QMetaObject *m, const QByteArray &name,
                             int argc, const QArgumentType *types);
    static int indexOfSlot(const QMetaObject *m, const QByteArray &name,
                           int argc, const QArgumentType *types);
    static int indexOfMethod(const QMetaObject *m, const QByteArray &name,
                             int argc, const QArgumentType *types);
    static int indexOfConstructor(const QMetaObject *m, const QByteArray &name,
                                  int argc, const QArgumentType *types);
    Q_CORE_EXPORT static QMetaMethod signal(const QMetaObject *m, int signal_index);
    Q_CORE_EXPORT static int signalOffset(const QMetaObject *m);
    Q_CORE_EXPORT static int absoluteSignalCount(const QMetaObject *m);
    Q_CORE_EXPORT static int signalIndex(const QMetaMethod &m);
    static bool checkConnectArgs(int signalArgc, const QArgumentType *signalTypes,
                                 int methodArgc, const QArgumentType *methodTypes);
    static bool checkConnectArgs(const QMetaMethodPrivate *signal,
                                 const QMetaMethodPrivate *method);

    static QList<QByteArray> parameterTypeNamesFromSignature(const char *signature);

#ifndef QT_NO_QOBJECT
    //defined in qobject.cpp
    enum DisconnectType { DisconnectAll, DisconnectOne };
    static void memberIndexes(const QObject *obj, const QMetaMethod &member,
                              int *signalIndex, int *methodIndex);
    static QObjectPrivate::Connection *connect(const QObject *sender, int signal_index,
                        const QMetaObject *smeta,
                        const QObject *receiver, int method_index_relative,
                        const QMetaObject *rmeta = 0,
                        int type = 0, int *types = 0);
    static bool disconnect(const QObject *sender, int signal_index,
                           const QMetaObject *smeta,
                           const QObject *receiver, int method_index, void **slot,
                           DisconnectType = DisconnectAll);
    static inline bool disconnectHelper(QObjectPrivate::Connection *c,
                                        const QObject *receiver, int method_index, void **slot,
                                        QMutex *senderMutex, DisconnectType = DisconnectAll);
#endif
};






1、    static int originalClone(const QMetaObject *obj, int local_method_index);  如果给出的  函数索引是克隆的返回原来的索引


int QMetaObjectPrivate::originalClone(const QMetaObject *mobj, int local_method_index)
{
    Q_ASSERT(local_method_index < get(mobj)->methodCount);
    int handle = get(mobj)->methodData + 5 * local_method_index;    handle等于函数所在字段偏移量   每个函数段5个int大小
    while (mobj->d.data[handle + 4] & MethodCloned) {
        Q_ASSERT(local_method_index > 0);
        handle -= 5;
        local_method_index--;                       //往回遍历 找到flags为0x20的  为克隆的
    }
    return local_method_index;
}



2、QByteArray QMetaObjectPrivate::decodeMethodSignature(const char *signature,QArgumentTypeArray &types);

 解析信号函数字符串, 将参数填充到QArgumentTypeArray 数组中, 并返回填充函数名称的QByteArray结构


QByteArray QMetaObjectPrivate::decodeMethodSignature(
        const char *signature, QArgumentTypeArray &types)
{
    Q_ASSERT(signature != 0);
    const char *lparens = strchr(signature, '(');
    if (!lparens)
        return QByteArray();
    const char *rparens = strrchr(lparens + 1, ')');
    if (!rparens || *(rparens+1))
        return QByteArray();
    int nameLength = lparens - signature;
    argumentTypesFromString(lparens + 1, rparens, types);    把函数参数()中的字符填充数组
    return QByteArray::fromRawData(signature, nameLength);   将函数名块直接作为 QByteArray的数据返回。不做拷贝
}

这里引用到的结构  QArgumentType  标识某一函数参数的类

class QArgumentType
{
public:
    QArgumentType(int type)
        : _type(type)
    {}
    QArgumentType(const QByteArray &name)
        : _type(qMetaTypeTypeInternal(name.constData())), _name(name)
    {}
    QArgumentType()
        : _type(0)
    {}

..............................
..............................略过
private:
    int _type;
    QByteArray _name;
};


typedef QVarLengthArray<QArgumentType, 10> QArgumentTypeArray;   最多支持10个参数



argumentTypesFromString  解析以逗号分隔的参数列表,填充QArgumentTypes 并加到 QArgumentTypeArray数组中

// Parses a string of comma-separated types into QArgumentTypes.
// No normalization of the type names is performed.
static void argumentTypesFromString(const char *str, const char *end,
                                    QArgumentTypeArray &types)
{
    Q_ASSERT(str <= end);
    while (str != end) {
        if (!types.isEmpty())
            ++str; // Skip comma
        const char *begin = str;
        int level = 0;
        while (str != end && (level > 0 || *str != ',')) {
            if (*str == '<')
                ++level;
            else if (*str == '>')
                --level;
            ++str;
        }
        types += QArgumentType(QByteArray(begin, str - begin));
    }
}



3、    static int indexOfSignalRelative(const QMetaObject **baseObject,
                                     const QByteArray &name, int argc,
                                     const QArgumentType *types);


返回信号相对于本类信号数组的索引值


int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
                                              const QByteArray &name, int argc,
                                              const QArgumentType *types)
{
    int i = indexOfMethodRelative<MethodSignal>(baseObject, name, argc, types);   调用全局模板函数indexOfMethodRelative来获取
#ifndef QT_NO_DEBUG
    const QMetaObject *m = *baseObject;
    if (i >= 0 && m && m->d.superdata) {
        int conflict = indexOfMethod(m->d.superdata, name, argc, types);
        if (conflict >= 0) {
            QMetaMethod conflictMethod = m->d.superdata->method(conflict);
            qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s",
                     conflictMethod.methodSignature().constData(),
                     objectClassName(m->d.superdata), objectClassName(m));    如果父类定义了相同的信号 则输出警告
        }
     }
 #endif
     return i;
}

template<int MethodType>
static inline int indexOfMethodRelative(const QMetaObject **baseObject,
                                        const QByteArray &name, int argc,
                                        const QArgumentType *types)
{
    for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) {
        Q_ASSERT(priv(m->d.data)->revision >= 7);
        int i = (MethodType == MethodSignal)
                 ? (priv(m->d.data)->signalCount - 1) : (priv(m->d.data)->methodCount - 1);  //根据模板参数 MethodType 来决定返回那种函数的索引。信号还是
        const int end = (MethodType == MethodSlot)                                             槽 还是成员函数
                        ? (priv(m->d.data)->signalCount) : 0;

        for (; i >= end; --i) {
            int handle = priv(m->d.data)->methodData + 5*i;
            if (methodMatch(m, handle, name, argc, types)) {            methodMatch 对类名  函数名  函数参数  数量  进行匹配
                *baseObject = m;
                return i;
            }
        }
    }
    return -1;
}
priv(X) 是个内联函数 将QMetaObject::data 从uint* 转换为 QMetaObjectPrivate类型的指针 


static inline Q_DECL_UNUSED const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }


4、indexOfSlotRelative  返回槽在其组中的索引

int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
                                            const QByteArray &name, int argc,
                                            const QArgumentType *types)
{
    return indexOfMethodRelative<MethodSlot>(m, name, argc, types);
}


5、indexOfSignal       indexOfSlot    indexOfMethod    返回信号 槽  成员函数索引   这些索引是包括其祖父类在内的整个(继承和私有的共同组成)大数组里的索引


indexOfConstructor

int QMetaObjectPrivate::indexOfSignal(const QMetaObject *m, const QByteArray &name,
                                      int argc, const QArgumentType *types)
{
    int i = indexOfSignalRelative(&m, name, argc, types);   返回在自身数组中的索引
    if (i >= 0)
        i += m->methodOffset();    返回继承的被放在祖父类staticMetaObject中的函数量
    return i;
}

int QMetaObjectPrivate::indexOfSlot(const QMetaObject *m, const QByteArray &name,
                                    int argc, const QArgumentType *types)
{
    int i = indexOfSlotRelative(&m, name, argc, types);
    if (i >= 0)
        i += m->methodOffset();
    return i;
}

int QMetaObjectPrivate::indexOfMethod(const QMetaObject *m, const QByteArray &name,
                                      int argc, const QArgumentType *types)
{
    int i = indexOfMethodRelative<0>(&m, name, argc, types);
    if (i >= 0)
        i += m->methodOffset();
    return i;
}

int QMetaObjectPrivate::indexOfConstructor(const QMetaObject *m, const QByteArray &name,
                                           int argc, const QArgumentType *types)
{
    for (int i = priv(m->d.data)->constructorCount-1; i >= 0; --i) {
        int handle = priv(m->d.data)->constructorData + 5*i;
        if (methodMatch(m, handle, name, argc, types))
            return i;
    }
    return -1;
}


6、QByteArray QMetaObjectPrivate::decodeMethodSignature    传递一个信号函数的字符串,将参数填充到QArgumentTypeArray中,将函数名填充QByteArray并返回



QByteArray QMetaObjectPrivate::decodeMethodSignature(
        const char *signature, QArgumentTypeArray &types)
{
    Q_ASSERT(signature != 0);
    const char *lparens = strchr(signature, '(');
    if (!lparens)
        return QByteArray();
    const char *rparens = strrchr(lparens + 1, ')');
    if (!rparens || *(rparens+1))
        return QByteArray();
    int nameLength = lparens - signature;
    argumentTypesFromString(lparens + 1, rparens, types);
    return QByteArray::fromRawData(signature, nameLength);
}


7、QMetaMethod QMetaObjectPrivate::signal        传递信号的索引  返回标记了信号函数的QMetaMethod对象


QMetaMethod QMetaObjectPrivate::signal(const QMetaObject *m, int signal_index)
{
    QMetaMethod result;
    if (signal_index < 0)
        return result;
    Q_ASSERT(m != 0);
    int i = signal_index;
    i -= signalOffset(m);
    if (i < 0 && m->d.superdata)
        return signal(m->d.superdata, signal_index);

    if (i >= 0 && i < priv(m->d.data)->signalCount) {
        result.mobj = m;
        result.handle = priv(m->d.data)->methodData + 5*i;
    }
    return result;
}


8、int QMetaObjectPrivate::absoluteSignalCount(const QMetaObject *m)     返回信号的个数 包括其基类的信号在内

int QMetaObjectPrivate::absoluteSignalCount(const QMetaObject *m)
{
    Q_ASSERT(m != 0);
    int n = priv(m->d.data)->signalCount;
    for (m = m->d.superdata; m; m = m->d.superdata)
        n += priv(m->d.data)->signalCount;
    return n;
}


9、bool QMetaObjectPrivate::checkConnectArgs(int signalArgc, const QArgumentType *signalTypes,
                                          int methodArgc, const QArgumentType *methodTypes)


bool QMetaObjectPrivate::checkConnectArgs(const QMetaMethodPrivate *signal,
                                          const QMetaMethodPrivate *method)


检测信号和要链接的函数 参数是否匹配



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值