元对象系统
Qt 的元对象系统提供了对象间通信的信号和槽机制,运行时类型信息和动态属性系统。
元对象系统基于以下三点
- QObject 类提供了一个基类,供可以利用元对象系统的对象使用。
- 使用 Q_OBJECT 宏来启用元对象功能,例如动态属性、信号和槽。
- 元对象编译器 (
moc
) 为每个 QObject 子类提供实现元对象功能所需的所有代码。
moc
工具读取 C++ 源文件。如果它发现一个或多个包含 Q_OBJECT 宏的类声明,它将生成另一个 C++ 源文件,该文件包含每个这些类的元对象代码。这个生成的源文件将要么被 #include
'd 到类的源文件中,要么更通常地与其实现编译并链接。
除了提供对象间通信(引入该系统的首要原因)的信号和槽机制外,元对象代码还提供了以下附加功能
- QObject::metaObject() 返回与类关联的 元对象。
- QMetaObject::className() 在运行时以字符串形式返回类名,无需通过 C++ 编译器支持原生运行时类型信息(RTTI)。
- QObject::inherits() 函数返回一个对象是否是继承自 QObject 继承树中指定类的类的实例。
- QObject::tr() 为 国际化 翻译字符串。
- QObject::setProperty() 和 QObject::property() 可以通过名称动态设置和获取属性。
- QMetaObject::newInstance() 构造该类的新实例。
还可以使用 qobject_cast() 在 QObject 类上执行动态转换。该 qobject_cast() 函数的行为类似于标准 C++ 的 dynamic_cast()
,优点是它不需要 RTTI 支持,并且可以在动态库边界之间工作。它尝试将其参数转换为目标尖括号中指定的指针类型,如果对象是正确的类型(在运行时确定),则返回非零指针,或者如果对象类型不兼容,则返回 nullptr
。
例如,假设 MyWidget
继承自 QWidget 并使用 Q_OBJECT 宏声明
QObject *obj = new MyWidget;
变量 obj
,类型为 QObject *
,实际上指向一个 MyWidget
对象,因此我们可以适当地进行类型转换
从 QObject 转换到 QWidget 是成功的,因为这个对象实际上是一个 MyWidget
,它是 QWidget 的子类。由于我们知道 obj
是一个 MyWidget
,我们也可以将其转换为 MyWidget *
MyWidget *myWidget = qobject_cast<MyWidget *>(obj);
转换为 MyWidget
是成功的,因为 qobject_cast() 对内置的 Qt 类型和非私有类型没有区别。
另一方面,转换为 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!")); }
虽然可以在不使用 Q_OBJECT 宏和元对象代码的情况下将 QObject 作为基类使用,但如果没有使用 Q_OBJECT 宏,则既没有信号和槽,也没有这里描述的其他功能。从元对象系统的角度来看,没有元代码的 QObject 子类与其最近的祖先(拥有元对象代码的)等价。这意味着比如,QMetaObject::className() 将返回你类的名称,而不是这个祖先的类名。
另请参阅 QMetaObject,Qt 的属性系统,和 信号和槽。
© 2024 Qt 公司。包含在本处的文档贡献的版权属于各自的拥有者。此处提供的文档是根据自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款授权的。Qt 和相应的标志是芬兰及/或其他国家 Qt 公司的商标。所有其他商标均属于各自所有者。