Chinaunix首页 | 论坛 | 博客
  • 博客访问: 304991
  • 博文数量: 174
  • 博客积分: 3061
  • 博客等级: 中校
  • 技术积分: 1740
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-04 22:43
文章分类

全部博文(174)

文章存档

2011年(54)

2010年(14)

2009年(30)

2008年(26)

2007年(27)

2006年(23)

我的朋友

分类: WINDOWS

2011-04-27 11:20:28

Qt MetaObject System详解之二:meta数据和数据结构 收藏

如果一个类的声明中包含Q_OBJECT宏,那么qmake将为这个类生成meta信息,这个信息在前一篇中所提到的moc文件中。这一篇通过解析这个一个示例moc文件来阐述这些meta信息的存储方式和格式;本篇先说明了一下QMetaObject的数据结构,然后呈现了一个简单的类TestObject类及其生成的moc文件,最后对这个moc文件个内容进行了详细解释。

QMetaObject的数据定义:

QMetaObject包含唯一的数据成员如下(见头文件qobjectdefs.h)

struct QMetaObject
{
private:
struct { // private data
        const QMetaObject *superdata;  //父类QMetaObject实例的指针
        const char *stringdata;                //一段字符串内存块,包含MetaObject信息之字符串信息
        const uint *data;                         //一段二级制内存块,包含MetaObject信息之二进制信息
        const void *extradata;                //额外字段,暂未使用
    } d;
}

 

QMetaObjectPrivate的数据定义:

QMetaObjectPrivate是QMetaObject的私有实现类,其数据定义部分如下(见头文件qmetaobject_p.h)。该数据结构全是int类型,一些是直接的int型信息,比如classInfoCount、methodCount等,还有一些是用于在QMetaObject的stringdata和data内存块中定位信息的索引值。下文结合这两个内存块的结构再分析个字段的含义。


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 
}

 

 

下文利用一个示例QObject子类及其moc文件,来分析QMetaObject的信息结构。

示例类TestObject:

TestObject类继承自QObject,定义了两个Property:propertyA,propertyB;两个classinfo:Author,Version;一个枚举:TestEnum。

  1. #include   
  2. class TestObject : public QObject  
  3. {  
  4.     Q_OBJECT  
  5.     Q_PROPERTY(QString propertyA  READ getPropertyA WRITE getPropertyA RESET resetPropertyA DESIGNABLE true SCRIPTABLE true STORED true USER false)  
  6.     Q_PROPERTY(QString propertyB  READ getPropertyB WRITE getPropertyB RESET resetPropertyB)  
  7.     Q_CLASSINFO("Author""Long Huihu")  
  8.     Q_CLASSINFO("Version""TestObjectV1.0")  
  9.     Q_ENUMS(TestEnum)  
  10. public:  
  11.     enum TestEnum {  
  12.         EnumValueA,  
  13.         EnumValueB  
  14.     };  
  15. public:  
  16.     TestObject();  
  17. signals:  
  18.     void clicked();  
  19.     void pressed();  
  20. public slots:  
  21.     void onEventA(const QString &);  
  22.     void onEventB(int );  
  23. }  

 

示例类TestObject的moc文件:


  1. static const uint qt_meta_data_TestObject[] = {  
  2.  // content:  
  3.        4,       // revision  
  4.        0,       // classname  
  5.        2,   14, // classinfo  
  6.        4,   18, // methods  
  7.        2,   38, // properties  
  8.        1,   44, // enums/sets  
  9.        0,    0, // constructors  
  10.        0,       // flags  
  11.        2,       // signalCount  
  12.  // classinfo: key, value  
  13.       22,   11,  
  14.       44,   29,  
  15.  // signals: signature, parameters, type, tag, flags  
  16.       53,   52,   52,   52, 0x05,  
  17.       63,   52,   52,   52, 0x05,  
  18.  // slots: signature, parameters, type, tag, flags  
  19.       73,   52,   52,   52, 0x0a,  
  20.       91,   52,   52,   52, 0x0a,  
  21.  // properties: name, type, flags  
  22.      113,  105, 0x0a095007,  
  23.      123,  105, 0x0a095007,  
  24.  // enums: name, flags, count, data  
  25.      133, 0x0,    2,   48,  
  26.  // enum data: key, value  
  27.      142, uint(TestObject::EnumValueA),  
  28.      153, uint(TestObject::EnumValueB),  
  29.        0        // eod  
  30. };  
  31. static const char qt_meta_stringdata_TestObject[] = {  
  32.     "TestObject\0Long Huihu\0Author\0"  
  33.     "TestObjectV1.0\0Version\0\0clicked()\0"  
  34.     "pressed()\0onEventA(QString)\0onEventB(int)\0"  
  35.     "QString\0propertyA\0propertyB\0TestEnum\0"  
  36.     "EnumValueA\0EnumValueB\0"  
  37. };  
  38. const QMetaObject TestObject::staticMetaObject = {  
  39.     { &QObject::staticMetaObject, qt_meta_stringdata_TestObject,  
  40.       qt_meta_data_TestObject, 0 }  
  41. };  
  42. #ifdef Q_NO_DATA_RELOCATION  
  43. const QMetaObject &TestObject::getStaticMetaObject() { return staticMetaObject; }  
  44. #endif //Q_NO_DATA_RELOCATION  
  45. const QMetaObject *TestObject::metaObject() const  
  46. {  
  47.     return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;  
  48. }  
  49. void *TestObject::qt_metacast(const char *_clname)  
  50. {  
  51.     if (!_clname) return 0;  
  52.     if (!strcmp(_clname, qt_meta_stringdata_TestObject))  
  53.         return static_cast<void*>(const_cast< TestObject*>(this));  
  54.     return QObject::qt_metacast(_clname);  
  55. }  
  56. int TestObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)  
  57. {  
  58.    ....
  59. }  
  60. // SIGNAL 0  
  61. void TestObject::clicked()  
  62. {  
  63.     QMetaObject::activate(this, &staticMetaObject, 0, 0);  
  64. }  
  65. // SIGNAL 1  
  66. void TestObject::pressed()  
  67. {  
  68.     QMetaObject::activate(this, &staticMetaObject, 1, 0);  
  69. }  
  70. QT_END_MOC_NAMESPACE  

qt_meta_data_TestObject::定义的正是QMetaObject::d.data指向的信息块;

qt_meta_stringdata_TestObject:定义的是QMetaObject::d.dataString指向的信息块;

const QMetaObject TestObject::staticMetaObject :定义TestObject类的MetaObject实例,从中可以看出QMetaObject各个字段是如何被赋值的;

const QMetaObject *TestObject::metaObject() const:重写了QObject::metaObject函数,返回上述的MetaObject实例指针。

TestObject::qt_metacall()是重写QObject的方法,依据传入的参数来调用signal&slot或访问property,动态方法调用属性访问正是依赖于这个方法,在第四篇中会再讲到该方法。

TestObject::clicked()和TestObject::pressed()正是对两个signal的实现,可见,signal其实就是一种方法,只不过这种方法由qt meta system来实现,不用我们自己实现。


 TestObject类的所有meta信息就存储在qt_meta_data_TestObject和qt_meta_stringdata_TestObject这两个静态数据中。QMetaObject的接口的实现正是基于这两块数据。下面就对这两个数据进行分块说明。

 

static const uint qt_meta_data_TestObject[] = { 

 

数据块一:
        // content:
       4,       // revision
       0,       // classname

       2,   14, // classinfo   

       4,   18, // methods

       2,   38, // properties
       1,   44, // enums/sets
       0,    0, // constructors
       0,       // flags
       2,       // signalCount

 

这块数据可以被看做meta信息的头部,正好和QMetaObjectPrivate数据结构相对应,在QMetaObject的实现中,正是将这块数据映射为QMetaObjectPrivate进行使用的。

第一行数据“4”:版本号;

第二行数据“0”:类型名,该值是qt_meta_stringdata_TestObject的索引,qt_meta_stringdata_TestObject[0]这个字符串不正是类型名“TestObject”吗。

第三行数据“2,14”,第一个表明有2个classinfo被定义,第二个是说具体的classinfo信息在qt_meta_data_TestObject中的索引,qt_meta_data_TestObject[14]的位置两个classinfo名值对的定义;

第四行数据“4,18”,指明method的信息,模式同上;

第五行数据“2,38”,指明property的信息,模式同上;
第六行数据“1,14”,指明enum的信息,模式同上。 

 

数据块二:
 // classinfo: key, value
      22,   11,
      44,   29,

classinfo信息块。第一行“22,11”,22表明qt_meta_stringdata_TestObject[22]处定义的字符串是classinfo的key,11表明qt_meta_stringdata_TestObject[11]处的字符串就是value。第二行“44,29”定义第二个classinfo。

 

数据块三:
 // signals: signature, parameters, type, tag, flags
      53,   52,   52,   52, 0x05,
      63,   52,   52,   52, 0x05,

signal信息块。第一行“53,   52,   52,   52, 0x05”定义第一个signal clicked()。qt_meta_stringdata_TestObject[53]是signal名称字符串。parameters 52, type 52, tag 52, flags如何解释暂未知。

 

数据块四:
 // slots: signature, parameters, type, tag, flags
      73,   52,   52,   52, 0x0a,
      91,   52,   52,   52, 0x0a,

slots信息,模式类似signal。

 

数据块五:
 // properties: name, type, flags
     113,  105, 0x0a095007,
     123,  105, 0x0a095007,

property性信息,模式类signal和slots,105如何和type对应暂未知。

 

数据块六:
 // enums: name, flags, count, data
     133, 0x0,    2,   48,
 // enum data: key, value
     142, uint(TestObject::EnumValueA),
     153, uint(TestObject::EnumValueB),

enum信息,第一行定义的是枚举名,flag,值的数目,data48不知是什么。

几行定义的是各枚举项的名称和值。名称同上都是qt_meta_stringdata_TestObject的索引值。


       0        // eod
};

 

 

阅读(682) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~