Qt MetaObject System详解

网上的资源比较乱,该文章整理自地址:http://www.xuebuyuan.com/735789.html

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信息。

1 QObject::metaObject()

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

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

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

QMetaObject提供的信息:

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

1,基本信息

1 struct Q_CORE_EXPORT QMetaObject
2 {
3     const char *className() const;
4     const QMetaObject *superClass() const;

2,classinfo:提供额外的类信息。其实就是一些名值对。用户可以在类的声明中以

1 Q_CLASSINFO(name, value)

方式添加

1     int classInfoOffset() const;
2     int classInfoCount() const;
3     int indexOfClassInfo(const char *name) const;
4     QMetaClassInfo classInfo(int index) const;

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

1     int constructorCount() const;
2     int indexOfConstructor(const char *constructor) const;
3     QMetaMethod constructor(int index) const;

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

1     int enumeratorOffset() const;
2     int enumeratorCount() const;
3     int indexOfEnumerator(const char *name) const;
4     QMetaEnum enumerator(int index) const;

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

1     int methodOffset() const;
2     int methodCount() const;
3     int indexOfMethod(const char *method) const;
4     int indexOfSignal(const char *signal) const;
5     int indexOfSlot(const char *slot) const;
6     QMetaMethod method(int index) const;

6、property:类型的属性信息

1     int propertyOffset() const;
2     int propertyCount() const;
3     int indexOfProperty(const char *name) const;
4     QMetaProperty property(int index) const; ////返回类中设置了USERflag的属性,(难道只能有一个这样的属性?)

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

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

下文来源: http://biancheng.dnbcw.info/linux/253557.html

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

QMetaObject的数据定义:

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

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

QMetaObjectPrivate的数据定义:

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

 1 struct QMetaObjectPrivate
 2 {
 3     int revision;
 4     int className;
 5     int classInfoCount, classInfoData;
 6     int methodCount, methodData;
 7     int propertyCount, propertyData;
 8     int enumeratorCount, enumeratorData;
 9     int constructorCount, constructorData; //since revision 2
10     int flags; //since revision 3
11     int signalCount; //since revision 4
12     // revision 5 introduces changes in normalized signatures, no new members
13     // revision 6 added qt_static_metacall as a member of each Q_OBJECT and inside QMetaObject itself
14 };

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

示例类TestObject:

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

 1     #include <QObject>
 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     #include "TestObject.h"
  2     #if !defined(Q_MOC_OUTPUT_REVISION)
  3     #error "The header file ‘TestObject.h‘ doesn‘t include <QObject>."
  4     #elif Q_MOC_OUTPUT_REVISION != 62
  5     #error "This file was generated using the moc from 4.6.0. It"
  6     #error "cannot be used with the include files from this version of Qt."
  7     #error "(The moc has changed too much.)"
  8     #endif
  9     QT_BEGIN_MOC_NAMESPACE
 10     static const uint qt_meta_data_TestObject[] = {
 11      // content:
 12            4,       // revision
 13            0,       // classname
 14            2,   14, // classinfo
 15            4,   18, // methods
 16            2,   38, // properties
 17            1,   44, // enums/sets
 18            0,    0, // constructors
 19            0,       // flags
 20            2,       // signalCount
 21      // classinfo: key, value
 22           22,   11,
 23           44,   29,
 24      // signals: signature, parameters, type, tag, flags
 25           53,   52,   52,   52, 0x05,
 26           63,   52,   52,   52, 0x05,
 27      // slots: signature, parameters, type, tag, flags
 28           73,   52,   52,   52, 0x0a,
 29           91,   52,   52,   52, 0x0a,
 30      // properties: name, type, flags
 31          113,  105, 0x0a095007,
 32          123,  105, 0x0a095007,
 33      // enums: name, flags, count, data
 34          133, 0x0,    2,   48,
 35      // enum data: key, value
 36          142, uint(TestObject::EnumValueA),
 37          153, uint(TestObject::EnumValueB),
 38            0        // eod
 39     };
 40     static const char qt_meta_stringdata_TestObject[] = {
 41         "TestObject\0Long Huihu\0Author\0"
 42         "TestObjectV1.0\0Version\0\0clicked()\0"
 43         "pressed()\0onEventA(QString)\0onEventB(int)\0"
 44         "QString\0propertyA\0propertyB\0TestEnum\0"
 45         "EnumValueA\0EnumValueB\0"
 46     };
 47     const QMetaObject TestObject::staticMetaObject = {
 48         { &QObject::staticMetaObject, qt_meta_stringdata_TestObject,
 49           qt_meta_data_TestObject, 0 }
 50     };
 51     #ifdef Q_NO_DATA_RELOCATION
 52     const QMetaObject &TestObject::getStaticMetaObject() { return staticMetaObject; }
 53     #endif //Q_NO_DATA_RELOCATION
 54     const QMetaObject *TestObject::metaObject() const
 55     {
 56         return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
 57     }
 58     void *TestObject::qt_metacast(const char *_clname)
 59     {
 60         if (!_clname) return 0;
 61         if (!strcmp(_clname, qt_meta_stringdata_TestObject))
 62             return static_cast<void*>(const_cast< TestObject*>(this));
 63         return QObject::qt_metacast(_clname);
 64     }
 65     int TestObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
 66     {
 67         _id = QObject::qt_metacall(_c, _id, _a);
 68         if (_id < 0)
 69             return _id;
 70         if (_c == QMetaObject::InvokeMetaMethod) {
 71             switch (_id) {
 72             case 0: clicked(); break;
 73             case 1: pressed(); break;
 74             case 2: onEventA((*reinterpret_cast< const QString(*)>(_a[1]))); break;
 75             case 3: onEventB((*reinterpret_cast< int(*)>(_a[1]))); break;
 76             default: ;
 77             }
 78             _id -= 4;
 79         }
 80     #ifndef QT_NO_PROPERTIES
 81           else if (_c == QMetaObject::ReadProperty) {
 82             void *_v = _a[0];
 83             switch (_id) {
 84             case 0: *reinterpret_cast< QString*>(_v) = getPropertyA(); break;
 85             case 1: *reinterpret_cast< QString*>(_v) = getPropertyB(); break;
 86             }
 87             _id -= 2;
 88         } else if (_c == QMetaObject::WriteProperty) {
 89             void *_v = _a[0];
 90             switch (_id) {
 91             case 0: getPropertyA(*reinterpret_cast< QString*>(_v)); break;
 92             case 1: getPropertyB(*reinterpret_cast< QString*>(_v)); break;
 93             }
 94             _id -= 2;
 95         } else if (_c == QMetaObject::ResetProperty) {
 96             switch (_id) {
 97             case 0: resetPropertyA(); break;
 98             case 1: resetPropertyB(); break;
 99             }
100             _id -= 2;
101         } else if (_c == QMetaObject::QueryPropertyDesignable) {
102             _id -= 2;
103         } else if (_c == QMetaObject::QueryPropertyScriptable) {
104             _id -= 2;
105         } else if (_c == QMetaObject::QueryPropertyStored) {
106             _id -= 2;
107         } else if (_c == QMetaObject::QueryPropertyEditable) {
108             _id -= 2;
109         } else if (_c == QMetaObject::QueryPropertyUser) {
110             _id -= 2;
111         }
112     #endif // QT_NO_PROPERTIES
113         return _id;
114     }
115     // SIGNAL 0
116     void TestObject::clicked()
117     {
118         QMetaObject::activate(this, &staticMetaObject, 0, 0);
119     }
120     // SIGNAL 1
121     void TestObject::pressed()
122     {
123         QMetaObject::activate(this, &staticMetaObject, 1, 0);
124     }
125     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的接口的实现正是基于这两块数据。下面就对这两个数据进行分块说明。

 1 static const uint qt_meta_data_TestObject[] = {
 2
 3 数据块一:
 4         // content:
 5        4,       // revision
 6        0,       // classname
 7
 8        2,   14, // classinfo
 9
10        4,   18, // methods
11
12        2,   38, // properties
13        1,   44, // enums/sets
14        0,    0, // constructors
15        0,       // flags
16        2,       // signalCount
17
18 这块数据可以被看做meta信息的头部,正好和QMetaObjectPrivate数据结构相对应,在QMetaObject的实现中,正是将这块数据映射为QMetaObjectPrivate进行使用的。
19
20 第一行数据“4”:版本号;
21
22 第二行数据“0”:类型名,该值是qt_meta_stringdata_TestObject的索引,qt_meta_stringdata_TestObject[0]这个字符串不正是类型名“TestObject”吗。
23
24 第三行数据“2,14”,第一个表明有2个classinfo被定义,第二个是说具体的 classinfo信息在qt_meta_data_TestObject中的索引,qt_meta_data_TestObject[14]的位置两个 classinfo名值对的定义;
25
26 第四行数据“4,18”,指明method的信息,模式同上;
27
28 第五行数据“2,38”,指明property的信息,模式同上;
29 第六行数据“1,14”,指明enum的信息,模式同上。
30
31 数据块二:
32  // classinfo: key, value
33       22,   11,
34       44,   29,
35
36 classinfo信息块。第一行“22,11”,22表明 qt_meta_stringdata_TestObject[22]处定义的字符串是classinfo的key,11表明 qt_meta_stringdata_TestObject[11]处的字符串就是value。第二行“44,29”定义第二个classinfo。
37
38 数据块三:
39  // signals: signature, parameters, type, tag, flags
40       53,   52,   52,   52, 0x05,
41       63,   52,   52,   52, 0x05,
42
43 signal信息块。第一行“53,   52,   52,   52, 0x05”定义第一个signal clicked()。qt_meta_stringdata_TestObject[53]是signal名称字符串。parameters 52, type 52, tag 52, flags如何解释暂未知。
44
45 数据块四:
46  // slots: signature, parameters, type, tag, flags
47       73,   52,   52,   52, 0x0a,
48       91,   52,   52,   52, 0x0a,
49
50 slots信息,模式类似signal。
51
52 数据块五:
53  // properties: name, type, flags
54      113,  105, 0x0a095007,
55      123,  105, 0x0a095007,
56
57 property性信息,模式类signal和slots,105如何和type对应暂未知。
58
59 数据块六:
60  // enums: name, flags, count, data
61      133, 0x0,    2,   48,
62  // enum data: key, value
63      142, uint(TestObject::EnumValueA),
64      153, uint(TestObject::EnumValueB),
65
66 enum信息,第一行定义的是枚举名,flag,值的数目,data48不知是什么。
67
68 几行定义的是各枚举项的名称和值。名称同上都是qt_meta_stringdata_TestObject的索引值。
69
70        0        // eod
71 };
72
73 static const char qt_meta_stringdata_TestObject[] = {
74
75 这块数据就是meta信息所需的字符串。是一个字符串的序列。
76     "TestObject\0Long Huihu\0Author\0"
77     "TestObjectV1.0\0Version\0\0clicked()\0"
78     "pressed()\0onEventA(QString)\0onEventB(int)\0"
79     "QString\0propertyA\0propertyB\0TestEnum\0"
80     "EnumValueA\0EnumValueB\0"
81 };

本篇从Qt MetaObject源代码解读相关接口的实现,这些接口都定义于qmetaobject.cpp中。

QMetaObject::className()

1 inline const char *QMetaObject::className() const
2 { return d.stringdata; }

d.stringdata就是那块字符串数据,包含若干c字符串(以‘\0‘)结尾。如果把d.stringdata当做一个c字符串指针的话,就是这个字符串序列的第一个字符串,正是类名。

QMetaObject::superClass()

1 inline const QMetaObject *QMetaObject::superClass() const
2 { return d.superdata; }

QMetaObject::classInfoCount()

 1 int QMetaObject::classInfoCount() const
 2 {
 3     int n = priv(d.data)->classInfoCount;
 4     const QMetaObject *m = d.superdata;
 5     while (m) {
 6         n += priv(m->d.data)->classInfoCount;
 7         m = m->d.superdata;
 8     }
 9     return n;
10 }

从代码可以看出,返回该类的所有classinfo数目,包括所有基类的。

函数priv是一个简单inline函数:

1 static inline const QMetaObjectPrivate *priv(const uint* data)
2 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }

d.data指向的是那块二进制信息,priv将d.data解释为QMetaObjectPrivate。

QMetaObjectPrivate是QMetaObject的私有实现类,其数据定义部分如下(见头文件qmetaobject_p.h)。和前一篇的示例moc文件内容一对应,其含义一目了然。

 1 struct QMetaObjectPrivate
 2 {
 3     int revision;
 4     int className;
 5     int classInfoCount, classInfoData;
 6     int methodCount, methodData;
 7     int propertyCount, propertyData;
 8     int enumeratorCount, enumeratorData;
 9     int constructorCount, constructorData; //since revision 2
10     int flags; //since revision 3
11     int signalCount; //since revision
12 }

QMetaObject:: classInfoOffset ()

 1 int QMetaObject::classInfoOffset() const
 2 {
 3     int offset = 0;
 4     const QMetaObject *m = d.superdata;
 5     while (m) {
 6         offset += priv(m->d.data)->classInfoCount;
 7         m = m->d.superdata;
 8     }
 9     return offset;
10 }

该类的含义是返回这个类所定义的classinfo的起始索引值,相当于它的祖先类所定义的classinfo的数量

QMetaObject:: classInfo  (int index)

 1 QMetaClassInfo QMetaObject::classInfo(int index) const
 2 {
 3     int i = index;
 4     i -= classInfoOffset();
 5     if (i < 0 && d.superdata)
 6         return d.superdata->classInfo(index);
 7
 8     QMetaClassInfo result;
 9     if (i >= 0 && i < priv(d.data)->classInfoCount) {
10         result.mobj = this;
11         result.handle = priv(d.data)->classInfoData + 2*i;
12     }
13     return result;
14 }
 1 class Q_CORE_EXPORT QMetaClassInfo
 2 {
 3 public:
 4     inline QMetaClassInfo() : mobj(0),handle(0) {}
 5     const char *name() const;
 6     const char *value() const;
 7     inline const QMetaObject *enclosingMetaObject() const { return mobj; }
 8 private:
 9     const QMetaObject *mobj;
10     uint handle;
11     friend struct QMetaObject;
12 };

这个代码的流程比较简单。priv(d.data)->classInfoData是classinfo的信息在d.data中的偏移;每条classinfo信息占2个UINT的大小,因此“priv(d.data)->classInfoData +
2*i”这个表达式的值就是第i个classinfo的信息在d.data中的偏移。

QMetaObject:: indexOfClassInfo  ()

 1 int QMetaObject::indexOfClassInfo(const char *name) const
 2 {
 3     int i = -1;
 4     const QMetaObject *m = this;
 5     while (m && i < 0) {
 6         for (i = priv(m->d.data)->classInfoCount-1; i >= 0; --i)
 7             if (strcmp(name, m->d.stringdata
 8                        + m->d.data[priv(m->d.data)->classInfoData + 2*i]) == 0) {
 9                 i += m->classInfoOffset();
10                 break;
11             }
12         m = m->d.superdata;
13     }
14     return i;
15 }

按照继承层次,从下往上寻找名字为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

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

QMetaMethod constructor  ( int index ) const

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

int indexOfConstructor  ( const char * constructor ) const

 1 int QMetaObject::indexOfConstructor(const char *constructor) const
 2 {
 3     if (priv(d.data)->revision < 2)
 4         return -1;
 5     for (int i = priv(d.data)->constructorCount-1; i >= 0; --i) {
 6         const char *data = d.stringdata + d.data[priv(d.data)->constructorData + 5*i];
 7         if (data[0] == constructor[0] && strcmp(constructor + 1, data + 1) == 0) {
 8             return i;
 9         }
10     }
11     return -1;
12 }
1 int enumeratorCount () const
2
3 int enumeratorOffset () const
4
5 QMetaEnum enumerator ( int index ) const
6
7 int indexOfEnumerator ( const char * name ) const

这组函数与classinfo那一组的实现及其相似。

1     int methodCount () const 略;
2     int methodOffset () const 略;
 1 QMetaMethod QMetaObject::method(int index) const
 2 {
 3     int i = index;
 4     i -= methodOffset();
 5     if (i < 0 && d.superdata)
 6         return d.superdata->method(index);
 7
 8     QMetaMethod result;
 9     if (i >= 0 && i < priv(d.data)->methodCount) {
10         result.mobj = this;
11         result.handle = priv(d.data)->methodData + 5*i;
12     }
13     return result;
14 }

该函数的实现方式也一目了然。

1 int indexOfMethod ( const char * method ) const 略;
 1 int QMetaObject::indexOfSignal(const char *signal) const
 2 {
 3     const QMetaObject *m = this;
 4     int i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal, false);
 5     if (i < 0) {
 6         m = this;
 7         i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal, true);
 8     }
 9     if (i >= 0)
10         i += m->methodOffset();
11     return i;
12 }
 1 int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
 2                                               const char *signal,
 3                                               bool normalizeStringData)
 4 {
 5     int i = indexOfMethodRelative<MethodSignal>(baseObject, signal, normalizeStringData);
 6 #ifndef QT_NO_DEBUG
 7     const QMetaObject *m = *baseObject;
 8     if (i >= 0 && m && m->d.superdata) {
 9         int conflict = m->d.superdata->indexOfMethod(signal);
10         if (conflict >= 0)
11             qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s",
12                      signal, m->d.superdata->d.stringdata, m->d.stringdata);
13     }
14 #endif
15     return i;
16 }
 1 template<int MethodType>
 2 static inline int indexOfMethodRelative(const QMetaObject **baseObject,
 3                                         const char *method,
 4                                         bool normalizeStringData)
 5 {
 6     for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) {
 7         int i = (MethodType == MethodSignal && priv(m->d.data)->revision >= 4)
 8                 ? (priv(m->d.data)->signalCount - 1) : (priv(m->d.data)->methodCount - 1);
 9         const int end = (MethodType == MethodSlot && priv(m->d.data)->revision >= 4)
10                         ? (priv(m->d.data)->signalCount) : 0;
11         if (!normalizeStringData) {
12             for (; i >= end; --i) {
13                 const char *stringdata = m->d.stringdata + m->d.data[priv(m->d.data)->methodData + 5*i];
14                 if (method[0] == stringdata[0] && strcmp(method + 1, stringdata + 1) == 0) {
15                     *baseObject = m;
16                     return i;
17                 }
18             }
19         } else if (priv(m->d.data)->revision < 5) {
20             for (; i >= end; --i) {
21                 const char *stringdata = (m->d.stringdata + m->d.data[priv(m->d.data)->methodData + 5 * i]);
22                 const QByteArray normalizedSignature = QMetaObject::normalizedSignature(stringdata);
23                 if (normalizedSignature == method) {
24                     *baseObject = m;
25                     return i;
26                 }
27             }
28         }
29     }
30     return -1;
31 }

可以看出,查找signal的特别之处在于,通过method元数据的第五项来判断这是不是一个signal。

1 int indexOfSlot ( const char * slot ) const 略;
2 int propertyCount () const 略;
3 int propertyOffset () const 略;
4 int indexOfProperty ( const char * name ) const 略;
 1 QMetaProperty QMetaObject::property(int index) const
 2 {
 3     int i = index;
 4     i -= propertyOffset();
 5     if (i < 0 && d.superdata)
 6         return d.superdata->property(index);
 7
 8     QMetaProperty result;
 9     if (i >= 0 && i < priv(d.data)->propertyCount) {
10         int handle = priv(d.data)->propertyData + 3*i;
11         int flags = d.data[handle + 2];
12         const char *type = d.stringdata + d.data[handle + 1];
13         result.mobj = this;
14         result.handle = handle;
15         result.idx = i;
16
17         if (flags & EnumOrFlag) {
18             result.menum = enumerator(indexOfEnumerator(type));
19             if (!result.menum.isValid()) {
20                 QByteArray enum_name = type;
21                 QByteArray scope_name = d.stringdata;
22                 int s = enum_name.lastIndexOf("::");
23                 if (s > 0) {
24                     scope_name = enum_name.left(s);
25                     enum_name = enum_name.mid(s + 2);
26                 }
27                 const QMetaObject *scope = 0;
28                 if (scope_name == "Qt")
29                     scope = &QObject::staticQtMetaObject;
30                 else
31                     scope = QMetaObject_findMetaObject(this, scope_name);
32                 if (scope)
33                     result.menum = scope->enumerator(scope->indexOfEnumerator(enum_name));
34             }
35         }
36     }
37     return result;
38 }

该函数的特别之处在于,如果这个propery是一个枚举类型的话,就为返回值QMetaPropery赋上正确QMetaEnum属性值。

 1 QMetaProperty QMetaObject::userProperty() const
 2 {
 3     const int propCount = propertyCount();
 4     for (int i = propCount - 1; i >= 0; --i) {
 5         const QMetaProperty prop = property(i);
 6         if (prop.isUser())
 7             return prop;
 8     }
 9     return QMetaProperty();
10 }

从这个函数的实现来看,一个QObject应该只会有一个打开USER flag的property。

时间: 2024-08-17 06:18:13

Qt MetaObject System详解的相关文章

Qt .pro文件 详解

1. TEMPLATE变量TEMPLATE描述了为建立目标文件而采用何种模板,即生成何种形式的Makefile文件.Qmake工具定义了5种模板:1. 应用程序App,为建立一个Qt应用程序创建Makefile文件;2. 库lib,为建立引用程序库而创建Makefile文件;3. 子工程 subdirs,为建立子目录下的目标文件创建一个Makefile文件,子目录通过变量SUBDIRS指定(子目录下的工程文件也需要指出使用何种模板);4. VC应用程序vcapp,为Visual Studio 生

Qt Quick 之 QML 与 C++ 混合编程详解

Qt Quick 技术的引入,使得你能够快速构建 UI ,具有动画.各种绚丽效果的 UI 都不在话下.但它不是万能的,也有很多局限性,原来 Qt 的一些技术,比如低阶的网络编程如 QTcpSocket ,多线程,又如 XML 文档处理类库 QXmlStreamReader / QXmlStreamWriter 等等,在 QML 中要么不可用,要么用起来不方便,所以呢,很多时候我们是会基于这样的原则来混合使用 QML 和 C++: QML 构建界面, C++ 实现非界面的业务逻辑和复杂运算. 请给

详解Qt动画框架(2)--- 实现网易云音乐tag切换

在详解Qt的动画框架(一)介绍了关于Qt动画框架一些基础知识,在这一节中,将会实际的看到有关与动画框架的实现,该案例主要实现的具体是网易云音乐tag的切换,网易云音乐中的切换如图所示: 本文介绍的方法也可以达到这种切换的简易效果. 设计动画框架 首先我们需要设计对于动画框架,其需要的动画效果是什么?对于上图,我们需要的是三个tag可以不停的切换,可以抽象为左移以及右移,即一个tag从一个矩形区域,移动到另外的矩形区域,那么对于Tag的承载体选为什么较为合适呢?因为我们仅仅只需要图片的显示,因此Q

qt安装详解

一.Qt  windows 环境安装的安装 第一步: 下载官方安装包,地址:http://www.qt.io/zh-hans/download-open-source/根据你电脑配置选在还是得安装包.下载下来之后双加按照提示安装.当安装成功之后,将qtcreator加入windows的环境变量.方法:右键  计算机>> 属性 >> 高级系统设置 >> 环境变量>> 系统变量中找到 path 将qt的环境安装目录添加进去结尾一定要加" ; 更详细地址

C语言中的system函数参数详解

http://blog.csdn.net/pipisorry/article/details/33024727 函数名: system 功   能: 发出一个DOS命令 用   法: int system(char *command); system函数已经被收录在标准c库中,可以直接调用 system()函数用于向操作系统传递控制台命令行,以WINDOWS系统为例,通过system()函数执行命令和在DOS窗口中执行命令的效果是一样的,所以只要在运行窗口中可以使用的命令都可以用SYSTEM()

qt的资源替换搜索QDir详解

QDir对跨平台的目录操作提供了很多的便利,为了更加方便的提供全局资源的查找,QDir提供了搜索路径替换功能,解决了资源搜索不便的问题,也能提高文件查找的效率. QDir通过已知的路径前缀去搜索并定位文件,搜索路径增加是有序的.从第一个设置的搜索路径开始,是不是觉得和cocos2d的路径搜索非常相似呢. 见如下QT的原版例子 QDir::setSearchPaths("icons", QStringList(QDir::homePath() + "/images")

Qt Quick之StackView详解(2)

在"StackView详解(1)"中,我们学习了StackView的基本用法,这次呢,我们来讲delegate的定制.被管理的View的生命周期.查找View等主题. 本文还会用到"StackView详解(1)"中的示例,如有需要可以回头看看. 附加属性 首先看看StackView提供的附加属性 Stack(后面会用到): Stack.index,index代表当前Item在StackView里的索引,从0开始哦,和StackView.depth不同哦,depth从

Qt Quick之StackView详解(1)

Qt Quick中有个StackView,我在<Qt Quick核心编程>一书中没有讲到,最近有人问起,趁机学习了一下,把它的基本用法记录下来. 我准备分两次来讲.第一次讲基本的用法,包括StackView的适用场景.基本属性和方法的用法.第二次讲一些稍微复杂点的东西,比如被StackView管理的view的生命周期.delegate定制.查找等. 示例会用到动态创建组建,可以参考我之前的文章"Qt Quick 组件与对象动态创建详解".也会用到锚布局,参考"Qt

JAVA 命令参数详解System.setProperty(

JAVA 命令参数详解: 1.-D<name>=<value> set a system property  设置系统属性. java -D参数简化加入多个jar java命令引入jar时可以-cp参数,但时-cp不能用通配符(多个jar时什么烦要一个个写,不能*.jar),面通常的jar都在同一目录,且多于1个.前些日子找到(发现)-Djava.ext.dirs太好. 如: java -Djava.ext.dirs=lib MyClass 可以在运行前配置一些属性,比如路径什么的