本篇从Qt MetaObject源代码解读相关接口的实现,这些接口都定义于qmetaobject.cpp中。QMetaObject::className()inline const char *QMetaObject::className() const{ return d.stringdata; }从前一篇可知,d.stringdata就是那块字符串数据,包含若干c字符串(以'\0')结尾。如果把d.stringdata当做一个c字符串指针的话,就是这个字符串序列的第一个字符串,正是类名。QMetaObject::superClass()inline const QMetaObject *QMetaObject::superClass() const{ return d.superdata; }QMetaObject::classInfoCount()int QMetaObject::classInfoCount() const{    int n = priv(d.data)->classInfoCount;    const QMetaObject *m = d.superdata;    while (m) {        n += priv(m->d.data)->classInfoCount;        m = m->d.superdata;    }    return n;}从代码可以看出,返回该类的所有classinfo数目,包括所有基类的。函数priv是一个简单inline函数:static inline const QMetaObjectPrivate *priv(const uint* data){ return reinterpret_cast(data); }由前一篇可知,d.data指向的是那块二进制信息,priv将d.data解释为QMetaObjectPrivate。QMetaObjectPrivate是QMetaObject的私有实现类,其数据定义部分如下(见头文件qmetaobject_p.h)。和前一篇的示例moc文件内容一对应,其含义一目了然。struct QMetaObjectPrivate{    int revision;    int className;    int classInfoCount, classInfoData;    int methodCount, methodData;    int propertyCount, propertyData;    int enumeratorCount, enumeratorData;    int constructorCount, constructorData; //since revision 2    int flags; //since revision 3    int signalCount; //since revision}QMetaObject::classInfoOffset ()int classInfoOffset () const{    int offset = 0;    const QMetaObject *m = d.superdata;    while (m) {        offset += priv(m->d.data)->classInfoCount;        m = m->d.superdata;    }    return offset;}该类的含义是返回这个类所定义的classinfo的起始索引值,相当于它的祖先类所定义的classinfo的数量。QMetaObject::classInfo (int index) QMetaClassInfo classInfo ( int index ) const{    int i = index;    i -= classInfoOffset();    if (i        return d.superdata->classInfo(index);    QMetaClassInfo result;    if (i >= 0 && i classInfoCount) {        result.mobj = this;        result.handle = priv(d.data)->classInfoData + 2*i;    }    return result;}这个代码的流程比较简单。priv(d.data)->classInfoData是classinfo的信息在d.data中的偏移;每条classinfo信息占2个UINT的大小,因此“priv(d.data)->classInfoData +2*i”这个表达式的值就是第i个classinfo的信息在d.data中的偏移。QMetaObject::indexOfClassInfo () int indexOfClassInfo ( const char * name ) const{    int i = -1;    const QMetaObject *m = this;    while (m && i        for (i = priv(m->d.data)->classInfoCount-1; i >= 0; --i)            if (strcmp(name, m->d.stringdata                       + m->d.data[priv(m->d.data)->classInfoData + 2*i]) == 0) {                i += m->classInfoOffset();                break;            }        m = m->d.superdata;    }    return i;}按照继承层次,从下往上寻找名字为name的classinfo。参考前一函数的解释,表达式m->d.data[priv(m->d.data)->classInfoData +2*i]的值是第i个classinfo信息的第一个32位值。该值是字符信息块d.stringdata中的索引值。因此m->d.stringdata+m->d.data[priv(m->d.data)->classInfoData +2*i]就是classinfo名称的字符串。int constructorCount () constint QMetaObject::constructorCount() const{    if (priv(d.data)->revision        return 0;    return priv(d.data)->constructorCount;}QMetaMethod constructor ( int index ) constQMetaMethod QMetaObject::constructor(int index) const{    int i = index;    QMetaMethod result;    if (priv(d.data)->revision >= 2 && i >= 0 && i constructorCount) {        result.mobj = this;        result.handle = priv(d.data)->constructorData + 5*i;    }    return result;}int indexOfConstructor ( const char * constructor ) constint QMetaObject::indexOfConstructor(const char *constructor) const{    if (priv(d.data)->revision        return -1;    for (int i = priv(d.data)->constructorCount-1; i >= 0; --i) {        if (strcmp(constructor, d.stringdata                   + d.data[priv(d.data)->constructorData + 5*i]) == 0) {            return i;        }    }    return -1;}int enumeratorCount () constint enumeratorOffset () constQMetaEnum enumerator ( int index ) constint indexOfEnumerator ( const char * name ) const这组函数与classinfo那一组的实现及其相似。   intmethodCount () const 略;   intmethodOffset () const 略;QMetaMethodmethod ( int index ) const{   int i = index;    i -= methodOffset();    if (i        return d.superdata->method(index);    QMetaMethod result;    if (i >= 0 && i methodCount) {        result.mobj = this;        result.handle = priv(d.data)->methodData + 5*i;    }    return result;}该函数的实现方式也一目了然。intindexOfMethod ( const char * method ) const 略;intindexOfSignal ( const char * signal ) const{   const QMetaObject *m = this;    int i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal);    if (i >= 0)        i += m->methodOffset();    return i;} 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;    }}可以看出,查找signal的特别之处在于,通过method元数据的第五项来判断这是不是一个signal。intindexOfSlot ( const char * slot ) const 略;intpropertyCount () const 略;intpropertyOffset () const 略;intindexOfProperty ( const char * name ) const 略; QMetaPropertyproperty ( int index ) const{    int i = index;    i -= propertyOffset();    if (i        return d.superdata->property(index);    QMetaProperty result;    if (i >= 0 && i propertyCount) {        int handle = priv(d.data)->propertyData + 3*i;        int flags = d.data[handle + 2];        const char *type = d.stringdata + d.data[handle + 1];        result.mobj = this;        result.handle = handle;        result.idx = i;        if (flags & EnumOrFlag) {            result.menum = enumerator(indexOfEnumerator(type));            if (!result.menum.isValid()) {                QByteArray enum_name = type;                QByteArray scope_name = d.stringdata;                int s = enum_name.lastIndexOf("::");                if (s > 0) {                    scope_name = enum_name.left(s);                    enum_name = enum_name.mid(s + 2);                }                const QMetaObject *scope = 0;                if (scope_name == "Qt")                    scope = &QObject::staticQtMetaObject;                else                    scope = QMetaObject_findMetaObject(this, scope_name);                if (scope)                    result.menum = scope->enumerator(scope->indexOfEnumerator(enum_name));            }        }    }    return result;}该函数的特别之处在于,如果这个propery是一个枚举类型的话,就为返回值QMetaPropery赋上正确QMetaEnum属性值。QMetaPropertyuserProperty () const{    const int propCount = propertyCount();    for (int i = propCount - 1; i >= 0; --i) {        const QMetaProperty prop = property(i);        if (prop.isUser())            return prop;    }    return QMetaProperty();}从这个函数的实现来看,一个QObject应该只会有一个打开USER flag的property。
10-18 18:50