Qt MetaObject sysmtem 詳解之三:QMetaObject介面實現

來源:互聯網
上載者:User
文章目錄
  • QMetaObject::className()
  • QMetaObject::superClass()
  • QMetaObject::classInfoCount()
  • QMetaObject::classInfoOffset ()
  • QMetaObject::classInfo (int index)
  • QMetaObject::indexOfClassInfo ()
  • int constructorCount () const
  • QMetaMethod constructor ( int index ) const
  • int indexOfConstructor ( const char * constructor ) const
  • intindexOfSignal ( const char * signal ) const
  • QMetaPropertyproperty ( int index ) const
  • QMetaPropertyuserProperty () const

本篇從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<const QMetaObjectPrivate*>(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 < 0 && d.superdata)
        return d.superdata->classInfo(index);

    QMetaClassInfo result;
    if (i >= 0 && i < priv(d.data)->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 < 0) {
        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 () const

int QMetaObject::constructorCount() const
{
    if (priv(d.data)->revision < 2)
        return 0;
    return priv(d.data)->constructorCount;
}

 

QMetaMethod constructor ( int index ) const

QMetaMethod QMetaObject::constructor(int index) const
{
    int i = index;
    QMetaMethod result;
    if (priv(d.data)->revision >= 2 && i >= 0 && i < priv(d.data)->constructorCount) {
        result.mobj = this;
        result.handle = priv(d.data)->constructorData + 5*i;
    }
    return result;
}

 

int indexOfConstructor ( const char * constructor ) const

int QMetaObject::indexOfConstructor(const char *constructor) const
{
    if (priv(d.data)->revision < 2)
        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 () const

int enumeratorOffset () const

QMetaEnum enumerator ( int index ) const

int indexOfEnumerator ( const char * name ) const

這組函數與classinfo那一組的實現及其相似。

 

 

 

   
intmethodCount () const 略;

   
intmethodOffset () const 略;

QMetaMethodmethod ( 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;

}

該函數的實現方式也一目瞭然。

 

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 < 0 && d.superdata)
        return d.superdata->property(index);

    QMetaProperty result;
    if (i >= 0 && i < priv(d.data)->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。

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.