zoukankan      html  css  js  c++  java
  • Qt之Meta-Object系统

    简述

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

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

    • QObject类:为objects提供了一个可以利用元对象系统的基类。

    • Q_OBJECT宏: 在类的私有部分声明这个宏可以启用元对象特性,例如:动态属性、信号与槽。

    • Meta-Object编译器(moc): 为每个QObject子类生成必要的代码来实现元对象特性。

    moc工具会读取C++源文件,如果发现有包含Q_OBJECT宏的类声明,就生成另外一个包含这些类的元对象代码的C++源文件。生成的源文件要么在类源文件里用#include包含,或者(更常见)与类的实现代码直接进行编译连接。

    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);

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

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

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

    因此,强烈建议所有QObject的子类都使用Q_OBJECT宏,不管实际上是否使用信号和槽,以及属性。

    更多参考

    • The Meta-Object System - 助手
  • 相关阅读:
    使用 ASP.NET Core MVC 创建 Web API(五)
    使用 ASP.NET Core MVC 创建 Web API(四)
    使用 ASP.NET Core MVC 创建 Web API(三)
    使用 ASP.NET Core MVC 创建 Web API(二)
    使用 ASP.NET Core MVC 创建 Web API(一)
    学习ASP.NET Core Razor 编程系列十九——分页
    学习ASP.NET Core Razor 编程系列十八——并发解决方案
    一个屌丝程序猿的人生(九十八)
    一个屌丝程序猿的人生(九十七)
    一个屌丝程序猿的人生(九十五)
  • 原文地址:https://www.cnblogs.com/itrena/p/5938246.html
Copyright © 2011-2022 走看看