元对象系统简介

Qt的元对象系统(The Meta-Object System)是Qt框架的核心特性之一,它为Qt提供了反射功能和动态属性管理。这个系统使得Qt能够在运行时处理对象的信息和特性,支持信号与槽机制动态属性系统运行时识别类型信息等功能。

元对象系统基于以下3点:

  • Object类:给所有使用元对象系统的对象提供了一个基类;
  • Q_OBJECT:用于启用元对象特性,写在类声明的私有部分中;
  • 元对象编译器moc:为每个QObject子类提供实现元对象特性所需的代码。

    moc是怎么工作的?
    moc读取一个c++源文件(如demo.cpp),若发现源文件中包含Q_OBJECT宏的类声明,就会生成另一个c++源文件(如moc_demo.cpp),其中包含每个类的元对象代码。生成的源文件编译并链接到类的实现中(也可以include到类的源文件中)。

QObject类

创建和销毁

QObject::QObject(QObject* parent = nullptr)
构造一个QObject对象。

  • 指定父对象:对象的父对象可看作对象的所有者,当父对象被销毁时,其析构函数也会销毁所有子对象;
  • 不指定父对象:即设为nullptr时,旧旧构造一个无父对象的对象,此时若对象是一个widget,则该widget将称为一个顶级窗口。

QObject::~QObject()
销毁对象及其所有子对象。
调用析构时,所有进出该对象的信号都会自动断开连接,事件队列也会删除该对象的所有挂起的发布事件;
删除QObject子类时,使用deleteLater()通常比delete更加安全

void QObject::deleteLater()
计划删除此对象。

什么是计划删除?
计划删除就是将当前对象标记为稍后删除,也就是在适当时安全删除该对象,其根据事件循环的状态来处理对象的删除,保证程序稳定性和安全性。

安全性
deleteLater()可多次安全调用。首次调用后,Qt会处理该对象的删除请求,并自动从事件队列中移除该对象相关的所有待处理事件。
deleteLater()是线程安全的。在多线程环境下,可以安全地从不同线程调用它。

工作机制

  1. 事件循环中的删除:
  • 当控制权返回到事件循环时,该对象会被删除。也就是说若程序正在运行一个事件循环(如用户输入、界面更新等)时,对象就会被删除。
  • 当事件循环运行前(如在QApplication::exec()之前)调用该函数,对象会在事件循环启动时被删除。
  • 当事件循环停止后调用该函数,该对象将不会被删除。
  • 当事件循环A中再调用了一个新事件循环A1(如打开模态对话框),不会立即删除对象,而是等到退出A1后并返回到调用该函数的A,才会进行删除。
  1. 线程中的删除:
    当对象在没有在运行事件循环的线程中时,对象会在线程结束时被适时删除(Qt4.8起)。

void QObject::destroyed(QObject *obj = nullptr)
(1)destroyed信号在对象被销毁之前立即发出,所有QPointer实例在这之后都会收到通知,并且该信号不能被阻塞

  • 信号发出时机及作用:在对象即将被销毁时发出,发出该信号后,收到信号的其他对象就得知某个对象即将被销毁,从而去释放资源或更新界面等。
  • QPointer:一种智能指针,它会监测所指向的QObject子对象的生命周期。所有指向该对象的QPointer实例,会在destroyed信号发出后被通知,当所指向的对象被销毁时,QPointer会自动将其内部的指针设置为nullptr,无需手动管理指针状态,因而使用Qpointer可以避免悬挂指针问题(dangling pointer)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include "MainWindow.h"
    #include <QApplication>
    #include <QPointer>
    #include <QDebug>
    #include <QTimer>

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    QPointer<MainWindow> w = new MainWindow();
    QObject::connect(w, &MainWindow::destroyed, [w](){
    // 等待事件循环更新状态
    QTimer::singleShot(0, [w](){
    qDebug() << "QPointer<MainWindow> is now: " << w; // nullptr
    });
    });
    delete w;
    return a.exec();
    }
    (2)对象的所有子对象在发出该信号后立即被销毁。

objectName

QString ObjectName;
该属性保存对象的名称。