现在的位置: 首页 > 综合 > 正文

(转载)Qt之美(二)元对象

2013年04月14日 ⁄ 综合 ⁄ 共 1943字 ⁄ 字号 评论关闭

除了D指针,Qt中另一个很有意思的部分就是Q_OBJECT宏了。该宏提供了对元对象的访问,使得能够使用比如信号和槽等QObject的更多特性。元对象提供了诸如类名、属性和方法等的信息,也被称为“反射”。


通过使用QMetaObject,我们能够用如下代码显示一些类的信息:

  1. QObject
    obj;
  2. const
    QMetaObject *metaObj = obj.metaObject();
  3. qDebug() <<

    "class name: "
    << metaObj->className();
  4. qDebug() <<

    "class info count: "
    <<
    metaObj->classInfoCount();
  5. qDebug() <<

    "methods: "
    ;
  6. //
    从QMetaObject::methodOffset()开始打印,使其不会显示父类的方法

  7. for
    (
    int
    i = metaObj->methodOffset(); i < metaObj->methodCount(); ++i)
  8. qDebug() << metaObj->method(i).methodType()
    <<
    " "
    << metaObj->method(i).signature();

由于C++并没有提供对这些信息的任何支持,Qt引入了元对象编译器(moc)来完成相应的工作。moc会读取每个头文件,如果发现其中定义的类是继承自QObject,且定义了Q_OBJECT宏,便会创建一个相应的C++源代码文件(moc_*.cpp),来完成这些工作。通过代码生成的工作,Qt不仅能够获得诸如Java等语言的灵活性,还能很好的保证继承自C++的性能和可扩展性

假设我们有如下所示的简单类:

  1. class
    MyObject :
    public
    QObject
  2. {
  3. Q_OBJECT
  4. public:
  5. explicit
    MyObject(QObject *parent = 0);
  6. void
    myFunc();
  7. public
    slots:
  8. void
    mySlot(
    int
    myParam);
  9. signals:
  10. void
    mySignal(
    int
    myParam);
  11. };

moc会自动创建以下信息:

  1. //
    保存在QMetaObject::d.data指向的空间,其起始部分是一个QMetaObjectPrivate结构体

  2. static
    const
    uint qt_meta_data_MyObject[] = {
  3. 5,

    // 版本号,其内部结构在Qt开发中有所改变

  4. 0,

    // 类名,其值为字符串qt_meta_stringdata_MyObject的偏移量

  5. //
    以下值为(数量,索引)对

  6. 0, 0,

    // 类信息

  7. 2, 14,

    // 这里定义了两个方法,其起始索引为14(即signal部分)

  8. 0, 0,

    // 属性

  9. 0, 0,

    // 枚举

  10. 0, 0,

    // 构造函数

  11. 0,

    // 标识

  12. 1,

    // signal数量

  13. //
    对于signal、slot和property,其signature和parameters为字符串qt_meta_stringdata_MyObject的偏移量

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

  15. 18, 10, 9, 9, 0x05,
  16. //
    slots: signature, parameters, type, tag, flags

  17. 32, 10, 9, 9, 0x0a,
  18. 0

    // eod

  19. };
  20. //
    保存在QMetaObject::d.stringdata指向的空间

  21. static
    const
    char
    qt_meta_stringdata_MyObject[] = {
  22. "MyObject/0/0myParam/0mySignal(int)/0"
  23. "mySlot(int)/0"
  24. };

以上信息,及其基类的相关信息,都保存在该类对应的元对象中:

  1. const
    QMetaObject MyObject::staticMetaObject = {
  2. { &QObject::staticMetaObject,

    // 指向其基类的元对象,保存在QMetaObject::d.superdata

  3. qt_meta_stringdata_MyObject,
    qt_meta_data_MyObject, 0 }
  4. };

这样,如果我们希望对QObject的对象进行类型转换,就不需使用开销较大的运算符dynamic_cast, 而能够直接使用qobject_cast。该模板函数利用了元对象系统的信息,避免了在运行时进行类型转换:

  1. template
    <
    class
    T>
    inline
    T qobject_cast(QObject *object)
  2. {
  3. #if
    !defined(QT_NO_QOBJECT_CHECK)

  4. reinterpret_cast(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast(object));
  5. #endif

抱歉!评论已关闭.