上一话题

应用程序主窗口

下一话题

模型/视图编程

元对象系统

An overview of Qt’s meta-object system and introspection capabilities.

Qt’s meta-object system provides the signals and slots mechanism for inter-object communication, run-time type information, and the dynamic property system.

元对象系统基于 3 件事:

  1. QObject 类为可以利用元对象系统的对象提供基类。

  2. Q_OBJECT 宏 (在类声明的私有部分内) 被用于启用元对象特征,如:动态特性、信号和槽。

  3. The Meta-Object Compiler ( moc ) 供应每 QObject 子类采用必要代码,以实现元对象特征。

moc 工具读取 C++ 源文件。若找到一个或多个类声明包含 Q_OBJECT 宏,它产生包含每个这些类的元对象代码的另一 C++ 源文件。这生成的源文件将 #include ‘d into the class’s source file or, more usually, compiled and linked with the class’s implementation.

除了提供 信号和槽 机制用于对象之间的通信 (引入系统的主要原因),元对象代码提供以下额外特征:

  • metaObject() returns the associated 元对象 为类。

  • className() returns the class name as a string at run-time, without requiring native run-time type information (RTTI) support through the C++ compiler.

  • inherits() function returns whether an object is an instance of a class that inherits a specified class within the QObject 继承树。

  • tr() and trUtf8() translate strings for internationalization.

  • setProperty() and property() dynamically set and get properties by name.

  • newInstance() constructs a new instance of the class.

也可以履行动态铸造使用 qobject_cast() on QObject 类。 qobject_cast() function behaves similarly to the standard 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 None if the object’s type is incompatible.

For example, let’s assume MyWidget 继承自 QWidget 和声明采用 Q_OBJECT 宏:

QObject *obj = new MyWidget;
										

obj 变量,类型 QObject * ,实际引用 MyWidget 对象,因此可以适当铸造:

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

铸造从 QObject to QWidget 成功,因为对象实际是 MyWidget ,这是子类对于 QWidget 。由于知道 obj MyWidget ,也可以将它铸造成 MyWidget * :

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

铸造成 MyWidget 成功因为 qobject_cast() makes no distinction between built-in Qt types and custom types.

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

铸造成 QLabel ,在其它方面,失败。然后,将指针设为 0。这使基于不同类型在运行时处理不同类型对象,成为可能:

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

虽然可以使用 QObject 作为基类不用 Q_OBJECT 宏及不用元对象代码,信号和槽及在此处描述的其它特征将不可用若 Q_OBJECT macro is not used. From the meta-object system’s point of view, a QObject 子类 (没有元代码) 相当于具有元对象代码的其最接近祖先。例如,这意味着 className() will not return the actual name of your class, but the class name of this ancestor.

因此,强烈推荐所有子类化的 QObject 使用 Q_OBJECT 宏,不管它们是否有实际使用信号,槽及特性。