作者:Q-Kevin @ http://www.qkevin.com

从本节开始,我们讲解 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》专栏文章是(http://www.qkevin.com)原创技术文章。
本系列专栏文章可随意转载,但必须保留本段声明和每一篇文章的原始地址。
作者保留版权,未经作者同意,不得用于任何商业用途

《Inside Qt Series》专栏文章总索引: http://www.qkevin.com/qt
本文原始地址:http://www.qkevin.com/archives/66

10-24 11:54