qt android meta data,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。

#include

classTestObject :publicQObject

{

Q_OBJECT

Q_PROPERTY(QString propertyA  READ getPropertyA WRITE getPropertyA RESET resetPropertyA DESIGNABLE trueSCRIPTABLEtrueSTOREDtrueUSERfalse)

Q_PROPERTY(QString propertyB  READ getPropertyB WRITE getPropertyB RESET resetPropertyB)

Q_CLASSINFO("Author","Long Huihu")

Q_CLASSINFO("Version","TestObjectV1.0")

Q_ENUMS(TestEnum)

public:

enumTestEnum {

EnumValueA,

EnumValueB

};

public:

TestObject();

signals:

voidclicked();

voidpressed();

publicslots:

voidonEventA(constQString &);

voidonEventB(int);

}#include

class TestObject : public QObject

{

Q_OBJECT

Q_PROPERTY(QString propertyA READ getPropertyA WRITE getPropertyA

RESET resetPropertyA DESIGNABLE true SCRIPTABLE true STORED true USER

false)

Q_PROPERTY(QString propertyB READ getPropertyB WRITE getPropertyB

RESET resetPropertyB)

Q_CLASSINFO("Author", "Long Huihu")

Q_CLASSINFO("Version", "TestObjectV1.0")

Q_ENUMS(TestEnum)

public:

enum TestEnum {

EnumValueA,

EnumValueB

};

public:

TestObject();

signals:

void clicked();

void pressed();

public slots:

void onEventA(const QString &);

void onEventB(int );

}

示例类TestObject的moc文件:

#include "TestObject.h"

#if !defined(Q_MOC_OUTPUT_REVISION)

#error "The header file 'TestObject.h' doesn't include ."

#elif Q_MOC_OUTPUT_REVISION != 62

#error "This file was generated using the moc from 4.6.0. It"

#error "cannot be used with the include files from this version of Qt."

#error "(The moc has changed too much.)"

#endif

QT_BEGIN_MOC_NAMESPACE

staticconstuint 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

// classinfo: key, value

22,   11,

44,   29,

// signals: signature, parameters, type, tag, flags

53,   52,   52,   52, 0x05,

63,   52,   52,   52, 0x05,

// slots: signature, parameters, type, tag, flags

73,   52,   52,   52, 0x0a,

91,   52,   52,   52, 0x0a,

// properties: name, type, flags

113,  105, 0x0a095007,

123,  105, 0x0a095007,

// enums: name, flags, count, data

133, 0x0,    2,   48,

// enum data: key, value

142, uint(TestObject::EnumValueA),

153, uint(TestObject::EnumValueB),

0        // eod

};

staticconstcharqt_meta_stringdata_TestObject[] = {

"TestObject\0Long Huihu\0Author\0"

"TestObjectV1.0\0Version\0\0clicked()\0"

"pressed()\0onEventA(QString)\0onEventB(int)\0"

"QString\0propertyA\0propertyB\0TestEnum\0"

"EnumValueA\0EnumValueB\0"

};

constQMetaObject TestObject::staticMetaObject = {

{ &QObject::staticMetaObject, qt_meta_stringdata_TestObject,

qt_meta_data_TestObject, 0 }

};

#ifdef Q_NO_DATA_RELOCATION

constQMetaObject &TestObject::getStaticMetaObject() {returnstaticMetaObject; }

#endif //Q_NO_DATA_RELOCATION

constQMetaObject *TestObject::metaObject()const

{

returnQObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;

}

void*TestObject::qt_metacast(constchar*_clname)

{

if(!_clname)return0;

if(!strcmp(_clname, qt_meta_stringdata_TestObject))

returnstatic_cast(const_cast(this));

returnQObject::qt_metacast(_clname);

}

intTestObject::qt_metacall(QMetaObject::Call _c,int_id,void**_a)

{

_id = QObject::qt_metacall(_c, _id, _a);

if(_id

return_id;

if(_c == QMetaObject::InvokeMetaMethod) {

switch(_id) {

case0: clicked();break;

case1: pressed();break;

case2: onEventA((*reinterpret_castconstQString(*)>(_a[1])));break;

case3: onEventB((*reinterpret_castint(*)>(_a[1])));break;

default: ;

}

_id -= 4;

}

#ifndef QT_NO_PROPERTIES

elseif(_c == QMetaObject::ReadProperty) {

void*_v = _a[0];

switch(_id) {

case0: *reinterpret_cast(_v) = getPropertyA();break;

case1: *reinterpret_cast(_v) = getPropertyB();break;

}

_id -= 2;

} elseif(_c == QMetaObject::WriteProperty) {

void*_v = _a[0];

switch(_id) {

case0: getPropertyA(*reinterpret_cast(_v));break;

case1: getPropertyB(*reinterpret_cast(_v));break;

}

_id -= 2;

} elseif(_c == QMetaObject::ResetProperty) {

switch(_id) {

case0: resetPropertyA();break;

case1: resetPropertyB();break;

}

_id -= 2;

} elseif(_c == QMetaObject::QueryPropertyDesignable) {

_id -= 2;

} elseif(_c == QMetaObject::QueryPropertyScriptable) {

_id -= 2;

} elseif(_c == QMetaObject::QueryPropertyStored) {

_id -= 2;

} elseif(_c == QMetaObject::QueryPropertyEditable) {

_id -= 2;

} elseif(_c == QMetaObject::QueryPropertyUser) {

_id -= 2;

}

#endif // QT_NO_PROPERTIES

return_id;

}

// SIGNAL 0

voidTestObject::clicked()

{

QMetaObject::activate(this, &staticMetaObject, 0, 0);

}

// SIGNAL 1

voidTestObject::pressed()

{

QMetaObject::activate(this, &staticMetaObject, 1, 0);

}

QT_END_MOC_NAMESPACE#include "TestObject.h"

#if !defined(Q_MOC_OUTPUT_REVISION)

#error "The header file 'TestObject.h' doesn't include ."

#elif Q_MOC_OUTPUT_REVISION != 62

#error "This file was generated using the moc from 4.6.0. It"

#error "cannot be used with the include files from this version of Qt."

#error "(The moc has changed too much.)"

#endif

QT_BEGIN_MOC_NAMESPACE

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

// classinfo: key, value

22, 11,

44, 29,

// signals: signature, parameters, type, tag, flags

53, 52, 52, 52, 0x05,

63, 52, 52, 52, 0x05,

// slots: signature, parameters, type, tag, flags

73, 52, 52, 52, 0x0a,

91, 52, 52, 52, 0x0a,

// properties: name, type, flags

113, 105, 0x0a095007,

123, 105, 0x0a095007,

// enums: name, flags, count, data

133, 0x0, 2, 48,

// enum data: key, value

142, uint(TestObject::EnumValueA),

153, uint(TestObject::EnumValueB),

0 // eod

};

static const char qt_meta_stringdata_TestObject[] = {

"TestObject\0Long Huihu\0Author\0"

"TestObjectV1.0\0Version\0\0clicked()\0"

"pressed()\0onEventA(QString)\0onEventB(int)\0"

"QString\0propertyA\0propertyB\0TestEnum\0"

"EnumValueA\0EnumValueB\0"

};

const QMetaObject TestObject::staticMetaObject = {

{ &QObject::staticMetaObject, qt_meta_stringdata_TestObject,

qt_meta_data_TestObject, 0 }

};

#ifdef Q_NO_DATA_RELOCATION

const QMetaObject &TestObject::getStaticMetaObject() { return staticMetaObject; }

#endif //Q_NO_DATA_RELOCATION

const QMetaObject *TestObject::metaObject() const

{

return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;

}

void *TestObject::qt_metacast(const char *_clname)

{

if (!_clname) return 0;

if (!strcmp(_clname, qt_meta_stringdata_TestObject))

return static_cast(const_cast< TestObject*>(this));

return QObject::qt_metacast(_clname);

}

int TestObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)

{

_id = QObject::qt_metacall(_c, _id, _a);

if (_id < 0)

return _id;

if (_c == QMetaObject::InvokeMetaMethod) {

switch (_id) {

case 0: clicked(); break;

case 1: pressed(); break;

case 2: onEventA((*reinterpret_cast< const QString(*)>(_a[1]))); break;

case 3: onEventB((*reinterpret_cast< int(*)>(_a[1]))); break;

default: ;

}

_id -= 4;

}

#ifndef QT_NO_PROPERTIES

else if (_c == QMetaObject::ReadProperty) {

void *_v = _a[0];

switch (_id) {

case 0: *reinterpret_cast< QString*>(_v) = getPropertyA(); break;

case 1: *reinterpret_cast< QString*>(_v) = getPropertyB(); break;

}

_id -= 2;

} else if (_c == QMetaObject::WriteProperty) {

void *_v = _a[0];

switch (_id) {

case 0: getPropertyA(*reinterpret_cast< QString*>(_v)); break;

case 1: getPropertyB(*reinterpret_cast< QString*>(_v)); break;

}

_id -= 2;

} else if (_c == QMetaObject::ResetProperty) {

switch (_id) {

case 0: resetPropertyA(); break;

case 1: resetPropertyB(); break;

}

_id -= 2;

} else if (_c == QMetaObject::QueryPropertyDesignable) {

_id -= 2;

} else if (_c == QMetaObject::QueryPropertyScriptable) {

_id -= 2;

} else if (_c == QMetaObject::QueryPropertyStored) {

_id -= 2;

} else if (_c == QMetaObject::QueryPropertyEditable) {

_id -= 2;

} else if (_c == QMetaObject::QueryPropertyUser) {

_id -= 2;

}

#endif // QT_NO_PROPERTIES

return _id;

}

// SIGNAL 0

void TestObject::clicked()

{

QMetaObject::activate(this, &staticMetaObject, 0, 0);

}

// SIGNAL 1

void TestObject::pressed()

{

QMetaObject::activate(this, &staticMetaObject, 1, 0);

}

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

};

static const char qt_meta_stringdata_TestObject[] = {

这块数据就是meta信息所需的字符串。是一个字符串的序列。

"TestObject\0Long Huihu\0Author\0"

"TestObjectV1.0\0Version\0\0clicked()\0"

"pressed()\0onEventA(QString)\0onEventB(int)\0"

"QString\0propertyA\0propertyB\0TestEnum\0"

"EnumValueA\0EnumValueB\0"

};

可以看出,meta信息在moc文件中以静态数据的形式被定义,其排列有点类似可执行文件中静态数据信息的排布。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值