QT的Meta-Object系统

原文:http://doc.qt.io/qt-5/metaobjects.html


Qt的meta-object system为对象间通信提供了signals和slots机制, 运行时类型检查(RTTI),和动态属性系统(dynamic property system)。


meta-object系统基于3件事情:
  1. QObject为利用meta-object系统的对象提供了一个基类;
  2. 在类声明的私有段的Q_OBJECT宏被用来enable meta-object系统,比如dynamic property,signals和slots;
  3. moc(Meta-Object Compiler)为每个QObject的子类提供必要的代码以实现meta-object的功能。
moc工具读取C++的源文件。若它发现有一个或多个类的声明含有Q_OBJECT宏,它就为每个类产生一个包含了meta-object代码的C++源文件。这个生成的源文件或者被包含在这个类的源文件中,或者更常见的是,被编译和与该类的实现进行链接。

除了为对象间通信提供signals和slots机制外(引入meta-object系统的主要原因),meta-object代码还提供如下的功能:
  • QObject::metaObject() 返回和该类相关的meta-object. 
  • QMetaObject::className() 可以在运行时以string的形式返回类名,而不需要编译器的运行时类型检查(RTTI)的支持。
  • QObject::inherits() 返回一个对象是否是一个类的实例,该类继承了QObject继承树种的某个类。
  • QObject::tr()和QObject::trUtf8() 为国际化而翻译字符串。
  • QObject::setProperty()和QObject::property() 通过名称动态地set和get属性;
  • QMetaObejct::newInstance() 构造该类的一个新的实例
在QObject的一系列类上使用qobject_cast()可以做到动态类型转换。qobject_cast()函数和标准C++的dynamic_cast()类似,不需要RTTI的支持,就能在不同的动态库之间工作。它试图将它的参数转换成在尖括号中指定的指针类型。如果转换成功,就返回非0指针;否则返回0. 
比如,假设MyWidget继承了QWidget,并且Q_OBJECT宏已经被声明:
QObject *obj = new MyWidget;
QWidget *widget = qobject_cast(obj);  // correct
MyWidget *myWidget = qobject_cast(obj);  // correct
QLabel *label = qobject_cast(obj);  // label is 0
转换到QLabel失败了。指针被设为0. 这使得在运行时基于类型来处理不同类型的对象成为可能:
if (QLabel *label = qobject_cast(obj)) {
    label->setText(tr("Ping"));
} else if (QPushButton *button = qobject_cast(obj)) {
    button->setText(tr("Pong!"));
}

使用QObject作为基类而不使用Q_OBJECT宏和meta-object代码是可能的。如果Q_OBJECT宏没有被使用,signals和slots,以及这里描述的其他功能就没有办法用了。从meta-object系统的观点来看,一个没有meta-object代码的QObject子类的对象,和它最近的祖先在meta-object code上是一致的。也就是说,比如,QMetaObject::className()将不会返回你的类的真正的名字,而是返回它的祖先的类名。
因此,我们强烈建议所有QObject的子类,都应该使用Q_OBJECT宏,无论它们是否使用了
signals、slots和properties. 

你可能感兴趣的:(C++,QT)