Qt对象树系统

QObject存在唯一构造QObject::QObject(QObject *parent = nullptr),这里的参数 parent 就构成了Qt的对象树系统。
对象树系统在GUI程序,尤其是GUI程序的内存管理中闪烁着智慧的光芒。就比如说,一个窗体里面有 按钮、标签、输入栏 等等组件,
现在我要删除一个窗体,很自然的我们会想到要将该窗体内的所有组件 按钮、标签、输入 等内容都要进行删除。
关联这个窗体及其内部的组件,使用的正是 parent 参数。内部的组件在创建时指定窗体为父对象,当父对象销毁时,内部窗体随之销毁。
明白了对象树的原理,我们还要知道其他几项比较重要的点:

  1. 父子对象是如何进行关联的。
  2. 对象树中构造和析构的顺序
  3. 关于析构存在的问题
  4. QWidget中对象的销毁

父子对象是如何进行关联的

  • 子对象通过构造函数里的 parent 参数执行其父对象
  • 父对象查找子类对象可以通过 findChild 和 findChildren
  • 子类对象可以通过 setParent 指定其父类对象,可以通过 parent 返回其父类的指针
  • 不同的模块接口不完全相同

对象树中构造和析构的顺序

和C++不完全相同。在对象树中,对象的创建与代码的逻辑结构有关,对象的析构与加入对象树的顺序有关。
也就是说,对象在 new 时被创建,如果一个对象在创建时候指定了 parent 参数,则父对象先于子类对象创建,否则按照new的顺序创建。
当父类对象被创建时,对象树系统建立。
子类对象通过 setParent 指定父类或者创建时指定 parent,子类对象被加入到对象树系统中。
当子类对象的父对象改变或子类对象被删除时,子类对象从当前对象树中移除。
当父类对象被删除时,父对象被析构,对象树中维护的子对象会按照加入对象树系统的先后顺序进行析构。

关于析构存在的问题

我们已经知道,当父类对象析构时,会将对象树中的子类对象一并进行析构。
当我们在父类对象被析构后,扔掉用子类的方法,就会导致程序崩溃

label->setParent(w);
delete w;
label->show();
//打印信息
ObjectTree.exe 崩溃

QWidget中对象的销毁

QWidget 也是 QObject 的子类,所以在 parent 机制上是没有区别的。然而实际使用时,对于 QWidget 和其派生类来说,在内存管理上要稍微复杂一些。因为 QWidget 需要和 QEventLoop 高度配合才能完成工作,我们举个例子来说明一下。

例如 QWidget 的关闭流程,首先用户点击关闭按钮触发 close() 槽,然后Qt向 widget 发送 QCloseEvent,默认的 QCloseEvent 会将 widget 隐藏起来,也就是hide()。我们可以看到,widget 的关闭实际是将其隐藏,而没有释放内存,虽然我们有时会重写 closeEvent 但也不会手动释放 widget。

所以需要设置 Qt::WA_DeleteOnClose 属性,那么会在 close 之后接着调用 widget 的析构函数,或者手动 delete。
————————————————
版权声明:本文为CSDN博主「lucky-billy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_34139994/article/details/105391611

对象树实例

//main.cpp objectwidget.cpp mypushbutton.cpp mylabel.cpp
//mypushbutton.h
#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H

#include <QPushButton>
#include <QDebug>
#include <QWidget>

class MyPushButton : public QPushButton
{
public:
    explicit MyPushButton(QWidget* parent = Q_NULLPTR);
    ~MyPushButton();
};

#endif // MYPUSHBUTTON_H

//mypushbutton.cpp
#include "MyPushButton.h"
MyPushButton::MyPushButton(QWidget* parent) : QPushButton(parent) {
    qDebug() << "MyPushButton::MyPushButton";
}  //MyPushButton

MyPushButton::~MyPushButton() {
    qDebug() << "MyPushButton::~MyPushButton";
}  //~MyPushButton

//mylabel.h
#ifndef MYLABEL_H
#define MYLABEL_H

#include <QLabel>
#include <QWidget>
#include <QDebug>

class MyLabel : public QLabel
{
public:
    explicit MyLabel(QWidget* parent = Q_NULLPTR);
    ~MyLabel();
};

#endif // MYLABEL_H

//mylabel.cpp
#include "MyLabel.h"
MyLabel::MyLabel(QWidget* parent) : QLabel(parent) {
    qDebug() << "MyLabel::MyLabel";
}  //MyLabel

MyLabel::~MyLabel() {
    qDebug() << "MyLabel::~MyLabel";
}  //~MyLabel

//objecttree.h
#ifndef OBJECTTREE_H
#define OBJECTTREE_H

#include <QMainWindow>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui { class ObjectTree; }
QT_END_NAMESPACE

class ObjectTree : public QMainWindow
{
    Q_OBJECT

public:
    ObjectTree(QWidget *parent = nullptr);
    ~ObjectTree();

private:
    Ui::ObjectTree *ui;
};
#endif // OBJECTTREE_H


//objecttree.cpp
#include "objecttree.h"
#include "ui_objecttree.h"

ObjectTree::ObjectTree(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::ObjectTree)
{
    //ui->setupUi(this);
    qDebug() << "ObjectTree::ObjectTree";
}

ObjectTree::~ObjectTree() {
    qDebug() << "ObjectTree::~ObjectTree";
    delete ui;
}

//main.cpp
#include "objecttree.h"
#include <QApplication>
#include "MyLabel.h"
#include "MyPushButton.h"

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    MyLabel* label = new MyLabel;
    MyPushButton* pBtn = new MyPushButton;
    ObjectTree* w = new ObjectTree;
    pBtn->setParent(w);
    label->setParent(w);
    label->setObjectName("label");
    pBtn->setObjectName("pBtn");
    //qDebug() << w->findChild("");
    qDebug() << w->findChildren<QWidget*>();
    delete pBtn;
    delete w;
    //label->show();
    return 0;
}
//输出
MyLabel::MyLabel
MyPushButton::MyPushButton
ObjectTree::ObjectTree
(QPushButton(0x1ae388dfd40, name="pBtn"), QLabel(0x1ae388df790, name="label"))
MyPushButton::~MyPushButton
ObjectTree::~ObjectTree
MyLabel::~MyLabel
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

fstarSea

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

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

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

打赏作者

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

抵扣说明:

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

余额充值