这个系列的几篇文章通过阅读Qt帮助文档和相关的源代码来学习研究Qt meta-object所提供的功能,及其实现的方式。

Qt meta-object系统基于三个方面:

 1、QObject提供一个基类,方便派生类使用meta-object系统的功能;

 2、Q_OBJECT宏,在类的声明体内激活meta-object功能,比如动态属性、信号、槽;

 3、Meta Object编译器(MOC),为每个QObject派生类生成代码,以支持meta-object功能。

QObject定义了从一个QObject对象访问meta-object功能的接口,Q_OBJECT宏用来告诉编译器该类需要激活meta-object功能,编译器在扫描一个源文件时,如果发现类的声明中有这个宏,就会生成一些代码来为支持meta-object功能——主要是生成该类对应MetaObject类以及对QObject的函数override。

QObject和QMetaObject:

顾名思义,QMetaObject包含了QObject的所谓的元数据,也就是QObject信息的一些描述信息:除了类型信息外,还包含QT中特有的signal&slot信息。

 QObject::metaObject()方法返回一个QObject对象对应的metaobject对象,注意这个方法是virtual方法。如上文所说,如果一个类的声明中包含了Q_OBJECT宏,编译器会生成代码来实现这个类对应的QMetaObject类,并重载QObject::metaObject()方法来返回这个QMetaObject类的实例引用。这样当通过QObject类型的引用调用metaObejct方法时,返回的是这个引用的所指的真实对象的metaobject。

如果一个类从QObject派生,确没有声明Q_OBJECT宏,那么这个类的metaobject对象不会被生成,这样这个类所声明的signalslot都不能使用,而这个类实例调用metaObject()返回的就是其父类的metaobject对象,这样导致的后果就是你从这个类实例获得的元数据其实都是父类的数据,这显然给你的代码埋下隐患。因此如果一个类从QOBject派生,它都应该声明Q_OBJECT宏,不管这个类有没有定义signal&slot和Property。

这样每个QObject类都有一个对应的QMetaObject类,形成一个平行的类型层次。

QMetaObject提供的信息:

下面通过QMetaObject的接口来解读QMetaObject提供的信息:

1、基本信息

     const char *className () const;

     const QMetaObject *superClass () const

2、classinfo: 提供额外的类信息。其实就是一些名值对。 用户可以在类的声明中以Q_CLASSINFO(name,value)方式添加。

     int classInfoCount () const
     int classInfoOffset () const

      QMetaClassInfo classInfo ( int index ) const

      int indexOfClassInfo ( const char * name ) const

3、contructor:提供该类的构造方法信息

     QMetaMethod constructor ( int index ) const
    int constructorCount () const

     int indexOfConstructor ( const char * constructor ) const

4、enum:描述该类声明体中所包含的枚举类型信息

    QMetaEnum enumerator ( int index ) const
   int enumeratorCount () const
   int enumeratorOffset () const

    int indexOfEnumerator ( const char * name ) const

5、method:描述类中所包含方法信息:包括property,signal,slot等,包括祖先类,如何组织暂时不确定。

    QMetaMethodmethod ( int index ) const
   intmethodCount () const
   intmethodOffset () const

    intindexOfMethod ( const char * method ) const
   intindexOfSignal ( const char * signal ) const
   intindexOfSlot ( const char * slot ) const

6、property:类型的属性信息

     QMetaPropertyproperty ( int index ) const
    intpropertyCount () const
    intpropertyOffset () const

     intindexOfProperty ( const char * name ) const

     QMetaPropertyuserProperty () const  //返回类中设置了USERflag的属性,(难道只能有一个这样的属性?)

注意:对于类里面定义的函数,构造函数,枚举,只有加上一些宏才表示你希望为方法提供meta信息。比如 Q_ENUMS用来注册宏,

Q_INVACABLE用来注册方法(包括构造函数)。Qt这么设计的原因应该是避免meta信息的臃肿。

10-18 18:54