Inside QT Series (五):元对象系统(Meta-Object System)

来源:互联网 发布:stm8数据手册 编辑:程序博客网 时间:2024/04/29 07:04
从本节开始,我们讲解 QT Meta-Object System 的功能,以及实现。

    在使用 QT 开发的过程中,大量的使用了 signal 和 slot. 比如,响应一个 button 的 click 事件,我们一般都写如下的代码:

class MyWindow : public QWidget
{
  Q_OBJECT
  public:
  MyWindow(QWidget* parent) : QWidget(parent)
  {
    QPushButton* btnStart = new QPushButton(“start”, this);
    connect(btnStart, SIGNAL(clicked()), SLOT(slotStartClicked()));
  }

private slots:
  void slotStartClicked();
};

void MyWindow:: slotStartClicked()
{
    // 省略
}

    在这段代码中,我们把 btnStart 这个 button 的clicked() 信号和 MyWindow 的 slotStartClicked() 这个槽相连接,当 btnStart 这个 button 被用户按下(click)的时候,就会发出一个 clicked() 的信号,然后,MyWindow:: slotStartClicked() 这个 slot 函数就会被调用用来响应 button 的 click 事件。

    这段代码是最为典型的 signal/slot 的应用实例,在实际的工作过程中,signal/slot 还有更为广泛的应用。准确的说,signal/slot 是QT提供的一种在对象间进行通讯的技术,那么,这个技术在QT 中是如何实现的呢?

    这就是 QT 中的元对象系统(Meta Object System)的作用,为了更好的理解它,让我先来对它的功能做一个回顾,让我们一起来揭开它神秘的面纱。


Meta-Object System 的基本功能

Meta Object System 的设计基于以下几个基础设施:

  • QObject 类
    作为每一个需要利用元对象系统的类的基类
  • Q_OBJECT 宏,
    定义在每一个类的私有数据段,用来启用元对象功能,比如,动态属性,信号和槽
  • 元对象编译器moc (the Meta Object Complier),
    moc 分析C++源文件,如果它发现在一个头文件(header file)中包含Q_OBJECT 宏定义,然后动态的生成另外一个C++源文件,这个新的源文件包含 Q_OBJECT 的实现代码,这个新的 C++ 源文件也会被编译、链接到这个类的二进制代码中去,因为它也是这个类的完整的一部分。通常,这个新的C++ 源文件会在以前的C++ 源文件名前面加上 moc_ 作为新文件的文件名。其具体过程如下图所示:


    除了提供在对象间进行通讯的机制外,元对象系统还包含以下几种功能

  • QObject::metaObject() 方法
    它获得与一个类相关联的 meta-object
  • QMetaObject::className() 方法
    在运行期间返回一个对象的类名,它不需要本地C++编译器的RTTI(run-time type information)支持
  • QObject::inherits() 方法
    它用来判断生成一个对象类是不是从一个特定的类继承出来,当然,这必须是在QObject类的直接或者间接派生类当中
  • QObject::tr() and QObject::trUtf8()
    这两个方法为软件的国际化翻译字符串
  • QObject::setProperty() and QObject::property()
    这两个方法根据属性名动态的设置和获取属性值


    除了以上这些功能外,它还使用qobject_cast()方法在QObject类之间提供动态转换,qobject_cast()方法的功能类似于标准C++的dynamic_cast(),但是qobject_cast()不需要RTTI的支持,


    在一个QObject类或者它的派生类中,我们可以不定义Q_OBJECT宏。如果我们在一个类中没有定义Q_OBJECT宏,那么在这里所提到的相应的功能在这个类中也不能使用,从meta-object的观点来说,一个没有定义Q_OBJECT宏的类与它最接近的那个祖先类是相同的,那就是所,QMetaObject::className() 方法所返回的名字并不是这个类的名字,而是与它最接近的那个祖先类的名字。所以,我们强烈建议,任何从QObject继承出来的类都定义Q_OBJECT宏。

下一节,我们来了解另一个重要的工具:Meta-Object Compiler

====================================
声明:
《Inside Qt  Series》专栏文章是Qt核心技术论坛(InsideQt.com)原创技术文章。
本系列专栏文章可随意转载,但必须保留本段声明和每一篇文章的原始地址。
未经作者同意,不得用于商业用途