Qt元对象系统(Meta-Object System)

Qt元对象系统(Meta-Object System)提供了信号与槽机制,用于对象间通信、运行时类型信息和动态属性系统。

元对象系统基于三个方面:

  1. QObject类:为objects提供了一个可以利用元对象系统的基类。
  2. Q_OBJECT宏: 声明在类的私有部分,该宏可以启用元对象特性,例如:动态属性、信号与槽。
  3. Meta-Object Compiler(moc): 为每个QObject子类提供必要的代码来实现元对象特性。

moc工具会读取C++源文件,如果发现一个或多个类声明包含了Q_OBJECT宏,就会生成另外一个包含这些类元对象代码的C++源文件。这些编译生成的源文件也被包含到类的源文件中,通常被编译和链接到类的实现中。

除了为对象间的通信提供信号与槽(引入元对象系统的主要原因)机制外,元对象还提供以下额外特性:

  • QObject::metaObject()返回类关联的meta-object对象。
  • QMetaObject::className()在运行时以字符串的形式返回类名,无需C++编译器提供本机运行时类别信息(RTTI)的支持。
  • QObject::inherits()返回是否一个对象是QObject继承树上一个类的实例。
  • QObject::tr()和QObject::trUtf8()翻译字符串用于国际化。
  • QObject::setProperty()和QObject::property()通过名称动态设置和获取属性。
  • QMetaObject::newInstance()构造类的一个新实例。

还可以使用qobject_cast()在QObject类上执行动态类型转换。qobject_cast()函数和标准C++的dynamic_cast()功能类似,它的优点在于:不需要RTTI支持,而且可以在动态库边界上运行。它尝试将它的参数转换成尖括号内指定的指针类型,如果对象类型正确则返回非零指针(在运行时确定);如果对象类型不兼容则返回0。

例如,假设MyWidget继承自QWidget,同时也声明了Q_OBJECT宏。

QObject *obj = new MyWidget;

QObject *类型的变量obj实际上指向一个MyWidget对象,因此,我们可以适当地进行类型转换:

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

因为obj实际上是一个MyWidget,而MyWidget是QWidget的子类,所以,从QObject转换为QWidget是成功的。因为知道了obj类型是MyWidget,那么我们也可以将其转换为MyWidget *:

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

该转换也是成功的,因为qobject_cast()并不区分内置Qt类型和自定义类型。

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

如上,转换到QLabel是失败的。这使得我们可以在运行时基于对象的类型做不同的操作:

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作为基类,但是像信号和槽以及上述描述的其它特性都将无法使用。从元对象系统的角度来看,一个没有元对象代码的QObject子类等同于它最接近的有元对象代码的祖先。这意味着,QMetaObject::className()将不会返回你的类的真实名称,而是返回其祖先的名字。

因此,强烈建议所有QObject的子类都使用Q_OBJECT宏,无论实际上是否使用信号槽或属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值