【Qt开发流程】之对象模型3:对象树及其所有权

描述

Qt对象树是一种基于父子关系的对象管理机制,用于管理Qt应用程序中的所有对象。在Qt中,每个对象都可以拥有一个或多个子对象,并且每个子对象只能属于一个父对象。每个对象的所有权(也称为生存期)由其父对象控制。当父对象销毁时,它们会自动销毁其所有子对象,以确保在程序结束之前释放所有内存。
对象在对象树中组织自己。当you使用另一个对象作为父对象创建QObject时,它被添加到父对象的children()列表中,并在父对象被删除时被删除。事实证明,这种方法非常适合GUI对象的需要。例如,QShortcut(键盘快捷键)是相关窗口的子窗口,因此当用户关闭该窗口时,快捷键也会被删除。
QWidgetQt Widgets模块的基本类,它扩展了父子关系。子部件通常也成为子部件,即它显示在其父部件的坐标系统中,并被其父部件的边界以图形方式剪切。例如,当应用程序在关闭消息框后删除消息框时,消息框的按钮和标签也会被删除,正如我们所希望的那样,因为按钮和标签是消息框的子框。
程序员也可以自己删除子对象,将自己从父对象中移除。例如,当用户删除工具栏时,可能导致应用程序删除其QToolBar对象之一,在这种情况下,工具栏的QMainWindow父组件将检测到更改并相应地重新配置其屏幕空间。
调试函数QObject:: dumpobjectreree()QObject::dumpObjectInfo()在应用程序看起来或行为异常时通常很有用。
QObject:: dumpobjectreree():

this->dumpObjectTree();

在这里插入图片描述
QObject::dumpObjectInfo():

checkBox->dumpObjectInfo();

在这里插入图片描述

实际应用

在实际应用中,可以通过以下几种方式创建对象树:

  1. 通过new运算符手动分配内存来创建对象,然后使用QObject的setParent()函数将它们移动到树中。

  2. 使用Qt的自动内存管理机制,例如Qt的容器类,这些类在使用时会自动管理对象的内存,使它们成为树中的子对象。

对象的构造和销毁顺序

当在堆上创建QObjects(即用new创建)时,可以以任何顺序从它们构造一个树,然后,树中的对象可以以任何顺序销毁。当树中的任何QObject被删除时,如果该对象有父对象,析构函数将自动从其父对象中删除该对象。如果对象有子对象,析构函数会自动删除每个子对象。无论销毁顺序如何,QObject都不会被删除两次。

当在堆栈上创建QObjects时,同样的行为也适用。通常情况下,破坏的顺序不会造成问题。如下面的代码片段:

  int main()
  {
      QWidget window;
      QPushButton quit("Quit", &window);
      ...
  }

父窗口和子窗口都是QObject,因为QPushButton继承了QWidget,而QWidget继承了QObject。这段代码是正确的:quit的析构函数不会被调用两次,因为c++语言标准(ISO/IEC 14882:2003)指定局部对象的析构函数以与其构造函数相反的顺序调用。因此,首先调用子进程的析构函数quit,并在调用window的析构函数之前将自己从父进程window中移除。

但是现在考虑一下如果我们交换构造顺序会发生什么,如下面代码所示:

    QPushButton quit("Quit");
    QWidget window;

    quit.setParent(&window);

在这种情况下,破坏的顺序会引起问题。父类的析构函数首先被调用,因为它是最后创建的。然后调用它的子孩子quit的析构函数,这是不正确的,因为quit是一个局部变量。当quit随后超出作用域时,它的析构函数将被再次调用,这次是正确的,但是损害已经造成了。

示例

#include <QtWidgets>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    QWidget *mainWidget = new QWidget; // 创建主窗口 Widget
    QVBoxLayout *layout = new QVBoxLayout(mainWidget); // 创建主窗口的布局管理器
        
    QLabel *label = new QLabel("Hello Qt!"); // 创建标签对象
    layout->addWidget(label); // 将标签对象添加到布局管理器中

    QPushButton *button = new QPushButton("Click me!"); // 创建按钮对象
    layout->addWidget(button); // 将按钮对象添加到布局管理器中

    mainWidget->show(); // 显示主窗口
    
    return app.exec(); // 进入 Qt 事件循环
}

如果希望将标签和按钮对象添加到主窗口的对象树中,可以使用QWidget的setParent()函数将它们添加为主窗口的子对象:

label->setParent(mainWidget);
button->setParent(mainWidget);

这样,当主窗口对象被销毁时,它们也会被自动销毁。

结论

努力不一定有收获,但是不努力一定会很舒服哦

  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FreeLikeTheWind.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值