元对象系统

Qt 的元对象系统为对象间通信、运行时类型信息及动态特性系统,提供信号和槽机制。

元对象系统基于 3 件事:

  1. QObject 类为可以利用元对象系统的对象提供基类。
  2. Q_OBJECT 宏 (在类声明的私有部分内) 被用于启用元对象特征,如:动态特性、信号和槽。
  3. Meta-Object Compiler ( moc ) 供应每 QObject 子类采用必要代码,以实现元对象特征。

moc tool reads a C++ source file. If it finds one or more class declarations that contain the Q_OBJECT macro, it produces another C++ source file which contains the meta-object code for each of those classes. This generated source file is either #include 'd into the class's source file or, more usually, compiled and linked with the class's implementation.

In addition to providing the 信号和槽 mechanism for communication between objects (the main reason for introducing the system), the meta-object code provides the following additional features:

It is also possible to perform dynamic casts using qobject_cast () on QObject classes. The qobject_cast () 函数行为类似于标准 C++ dynamic_cast() , with the advantages that it doesn't require RTTI support and it works across dynamic library boundaries. It attempts to cast its argument to the pointer type specified in angle-brackets, returning a non-zero pointer if the object is of the correct type (determined at run-time), or 0 if the object's type is incompatible.

例如,让我们假定 MyWidget 继承自 QWidget and is declared with the Q_OBJECT macro:

    QObject *obj = new MyWidget;
							

obj variable, of type QObject * , actually refers to a MyWidget object, so we can cast it appropriately:

    QWidget *widget = qobject_cast<QWidget *>(obj);
							

The cast from QObject to QWidget is successful, because the object is actually a MyWidget , which is a subclass of QWidget . Since we know that obj MyWidget , we can also cast it to MyWidget * :

    MyWidget *myWidget = qobject_cast<MyWidget *>(obj);
							

The cast to MyWidget is successful because qobject_cast () makes no distinction between built-in Qt types and custom types.

    QLabel *label = qobject_cast<QLabel *>(obj);
    // label is 0
							

The cast to QLabel , on the other hand, fails. The pointer is then set to 0. This makes it possible to handle objects of different types differently at run-time, based on the type:

    if (QLabel *label = qobject_cast<QLabel *>(obj)) {
        label->setText(tr("Ping"));
    } else if (QPushButton *button = qobject_cast<QPushButton *>(obj)) {
        button->setText(tr("Pong!"));
    }
							

While it is possible to use QObject as a base class without the Q_OBJECT macro and without meta-object code, neither signals and slots nor the other features described here will be available if the Q_OBJECT macro is not used. From the meta-object system's point of view, a QObject subclass without meta code is equivalent to its closest ancestor with meta-object code. This means for example, that QMetaObject::className () will not return the actual name of your class, but the class name of this ancestor.

Therefore, we strongly recommend that all subclasses of QObject 使用 Q_OBJECT macro regardless of whether or not they actually use signals, slots, and properties.

另请参阅 QMetaObject , Qt's Property System ,和 信号和槽 .