Qt扫盲-Qt 元对象系统记录

Qt 元对象系统记录

  • 一、概述

一、概述

Qt的元对象系统提供了对象间通信的信号和槽机制、运行时类型信息和动态属性系统。就是动态的获取一些对象属性之类的,我经常会用到。

元对象系统基于三件事:

  1. QObject类为可以利用元对象系统的对象提供了一个基类。
  2. 类声明的private段中的Q_OBJECT宏用于启用元对象特性,如动态属性、信号和槽。
  3. 元对象编译器(moc)为每个QObject子类提供了实现元对象功能所需的代码。

这个就是要求我们在写自己的类的时候要继承 自 QObject 同时添加 Q_OBJECT 宏就好。

moc工具读取 c++ 源文件。如果它找到一个或多个包含 Q_OBJECT 宏的类声明,它会生成另一个包含每个类的元对象代码的c++源文件。这个生成的源文件要么 #include 到类的源文件中,要么,更常见的是,编译并链接到类的实现。
除了提供对象之间通信的信号和槽机制(引入该系统的主要原因),元对象代码还提供了下列额外功能。

  • QObject::metaObject() 返回类的关联元对象,这个元对象属性。
QObject *obj = new QPushButton;
obj->metaObject()->className();             // returns "QPushButton"

QPushButton::staticMetaObject.className();  // returns "QPushButton"
  • QMetaObject::className()在运行时以字符串的形式返回类名,而不需要c++编译器对原生运行时类型信息(RTTI)的支持。
  • QObject::inherits() 函数返回一个对象是否是QObject继承树中继承指定类的类的实例。
QTimer *timer = new QTimer;         // QTimer inherits QObject
timer->inherits("QTimer");          // returns true
timer->inherits("QObject");         // returns true
timer->inherits("QAbstractButton"); // returns false

// QVBoxLayout inherits QObject and QLayoutItem
QVBoxLayout *layout = new QVBoxLayout;
layout->inherits("QObject");        // returns true
layout->inherits("QLayoutItem");    // returns true (even though QLayoutItem is not a QObject)
  • QObject::tr() 和 QObject::trUtf8() 将字符串转换为国际化。
  • QObject::setProperty() 和 QObject::property() 动态地通过名称设置和获取属性。
  • QMetaObject::newInstance() 构造类的一个新实例。

还可以使用 qobject_cast() 对QObject类执行动态强制转换。qobject_cast( )函数的行为类似于标准c++ dynamic_cast(),其优点是它不需要RTTI支持,并且可以跨动态库边界工作。它尝试将其参数转换为尖括号中指定的指针类型,如果对象的类型正确(在运行时确定),则返回一个非零指针,如果对象的类型不兼容,则返回nullptr。

例如,假设MyWidget继承自QWidget,并用Q_OBJECT宏声明:

QObject *obj = new MyWidget;

类型为QObject *的obj变量实际上引用了一个MyWidget对象,因此我们可以适当地校正它:

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

从QObject转换到QWidget是成功的,因为对象实际上是一个MyWidget,它是QWidget的子类。因为我们知道obj是一个MyWidget,我们也可以将它强制转换为MyWidget *:

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

转换到MyWidget是成功的,因为qobject_cast()没有区分内置Qt类型和自定义类型。

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!"));
}

虽然可以在没有Q_OBJECT宏和元对象代码的情况下使用QObject作为基类,但如果没有使用Q_OBJECT宏,则信号和插槽以及这里描述的其他功能都不可用。从元对象系统的角度来看,没有元代码的QObject子类等同于它有元对象代码的最近的祖先。这意味着,例如,QMetaObject::className()不会返回你的类的实际名称,而是这个祖先的类名。
因此,我们强烈建议QObject的所有子类使用Q_OBJECT宏,无论它们是否实际使用信号、槽和属性。

你可能感兴趣的:(#,▶,Qt扫盲,Qt对象模型,Qt元对象模型,Meta-Object,MetaObjectSyste)