The Meta-Object System:元对象系统

发布于:2022-12-15 ⋅ 阅读:(972) ⋅ 点赞:(0)

元对象系统       

        Qt 的元对象系统为对象间通信、运行时类型信息和动态属性系统提供了信号和槽机制。

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

  1. QObject 类为可以利用元对象系统的对象提供基类。
  2. 类声明的私有部分中的 Q_OBJECT 宏用于启用元对象功能,例如动态属性、信号和插槽。
  3. Meta-Object Compiler () 为每个 QObject 子类提供必要的代码来实现元对象 features.moc。

        该工具读取C++源文件。如果它找到一个或多个包含Q_OBJECT宏的类声明,它将生成另一个C++源文件,其中包含每个类的元对象代码。生成的源文件要么被嵌入到类的源文件中,要么更通常地被编译并与类的实现链接。

元对象操作与信息获取

        除了为对象之间的通信提供信号和插槽机制(引入系统的主要原因)之外,元对象代码还提供以下附加功能: 

  1. QObject::metaObject() 返回类的关联元对象。
  2. QMetaObject::className() 在运行时将类名作为字符串返回,而不需要通过 C++ 编译器支持本机运行时类型信息 (RTTI)。
  3. QObject::inherits() 函数返回对象是否是继承 QObject 继承树中指定类的类的实例。
  4. QObject::tr() 为国际化翻译字符串。
  5. QObject::setProperty() 和 QObject::property() 按名称动态设置和获取属性。
  6. QMetaObject::newInstance() 构造类的一个新实例。

动态类型转换

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

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

 QObject *obj = new MyWidget;

        类型的变量实际上是指一个对象,所以我们可以适当地转换它:objQObject  *MyWidget

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

        从 QObject 到 QWidget 的转换是成功的,因为对象实际上是 a ,它是 QWidget 的子类。由于我们知道这是 a ,我们也可以将其转换为 :MyWidgetobjMyWidgetMyWidget *

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

        转换成功是因为 qobject_cast() 不区分内置 Qt 类型和自定义类型。MyWidget

 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 宏,无论它们是否实际使用信号、槽和属性


网站公告

今日签到

点亮在社区的每一天
去签到

热门文章