【QT-百日筑基篇】找寻安静的落脚处,选择合适的功法进行修炼-QT深度了解对象树的特性

|------|-----------------------------------------------------------------------|
| | 链接 |
| 作者主页 | 点击 |
| 代码储存 | 点击 |


关于在QT中对象析构的问题:

在QT中我们一般要使用一些控件的化,要么手动new, 手动new的时候我们在程序结束的时候没有使用delete来进行析构。

形如:

cpp 复制代码
QLabel*labe=new QLabel(this);

那么这样会造成内存的泄露吗???

首先我们需要先进行了解我们在new的时候加上了一个this指针是将这个对象挂在对象树上来进行对应的处理的, 在对象树上会进行一系列的操作, 会将对象进行析构统一的处理的。

这颗对象树是一颗N叉数。

当然这里还有一个问题:

我们为什么要在堆上进行对象树的管理而不在栈上进行管理呢?

cpp 复制代码
    //方法一:在堆上进行开空间(推荐这种方式的使用)
    //QLabel*labe=new QLabel(this);
    //方法二:在栈上进行空间的开辟
    //QLabel label;

那我们就带这这些问题好好的去了解对象树吧。

初识对象树:

我帮你把这段核心内容整理成统一、清晰、易记的版本,完全保留原意,格式和表述一致:

◦ 创建 QObject 对象时,其构造函数会接收一个 QObject* 类型的参数,这个参数就是 parent(父对象指针)

◦ 为新创建的 QObject 指定父对象后,该对象会自动添加到父对象的 children() 列表中

◦ 父对象被析构(销毁)时,会自动析构其 children() 列表中的所有子对象 ,无需手动释放。

◦ 重要注意:这里的父子对象是组合 / 包含关系不是 C++ 继承意义上的父类与子类

我们在创建项目的时候, 会有一个QWidget, 而其他的控件(Label)在类中都是继承了QWidget

• QWidget是能够在屏幕上显⽰的⼀切组件的⽗类。

◦ QWidget继承⾃QObject,因此也继承了这种对象树关系。⼀个孩⼦⾃动地成为⽗组件的⼀ 个⼦组件。因此,它会显⽰在⽗组件的坐标系统中,被⽗组件的边界剪裁。例如,当⽤⼾关闭 ⼀个对话框的时候,应⽤程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该 ⼀起被删除。事实就是如此,因为这些都是对话框的⼦组件。

◦ 当然,我们也可以⾃⼰删除⼦对象,它们会⾃动从其⽗对象列表中删除。⽐如,当我们删除了 ⼀个⼯具栏时,其所在的主窗⼝会⾃动将该⼯具栏从其⼦对象列表中删除,并且⾃动调整屏幕 显⽰。

我们就类似的得到了这样的一个结构:

其对应的一个树形结构为:

对象树的意义:

对象树存在的意义就是将我们创建的对象进行统一的管理起来, 等我们使用完找到一个合适的时机,来进行一个统一的释放,提前释放会导致一些界面上的控件会得不到合适的机会进行释放(界面会不存在) 。它的释放的大概时机是等到我们图形化界面的窗口进行销毁的时候这些对象会统一的进行销毁。

为什么在堆上进行开空间而不再栈上进行空间的开辟:

因为栈销毁的生命周期结束的时候就会将栈的空间进行回收。而堆是对象树进行统一销毁的时候是将空间统一回收的。在栈上空间会提前进行释放。 这样会导致界面的消失。所以我们在堆上开空间然后进行统一的销毁这样会更好。

模拟实现对象树的销毁

在这一快光说其实并没有什么用我们只有见一见才能得知真假。所以我们就来进行模拟实现一下对应的对象树销毁的过程。

我们先快速的创建好项目, 在这里我们需要手动的创建一个文件(头文件和源文件)实现一个mylabel

头文件与源文件的创建 :

选择新建文件:

选择c++ 和 c++对象:

选择文件名字,选择父类的文件这里我们发现Base里没有QLabel那我们就自己手动的进行创建吧:

下一步完成即可。

完善MyLabel:

我们发现对应的QLabel他不认识,那么我们需要手动的包一下**<QLabel>的头文件**。

myqlabel中的操作为

因为myqlabel的父类是QLabel, 而QLabel的父类是QWidget, 所以我用QWidget来进行接受的话他们对应的继承关系会进行对应的切片操作, 所以这样写的好处是将我所创建的mylabel对象进行切片,并挂在对象树上后期进行统一的释放。 后面的部分是为了去调用父类QLabel的构造函数进行初始化。

cpp 复制代码
myqlabel::myqlabel(QWidget* parent) : QLabel(parent)
{

}

当然这样的话我们是不是该写析构函数了, 在c++中调用析构函数才能看见对应的函数是否进行了析构所以。

析构函数的书写:

我们在头文件进行了定义可以使用快捷键来进行快速的在cpp文件中进行定义。

快捷键:【alt】+【enter】 【F4】 : 头文件和源文件进行切换

我们析构和cpp一般的类的析构保持一致

cpp 复制代码
myqlabel::~myqlabel()
{
       std::cout<<"myqlabel 已被销毁"<<std::endl;
}

我们这样测试一下:

这时候我们就在对应的widget中进行对应的文本的设置。

这时候我们进行运行

点击X来结束这个程序的执行,然后我们就能发现对象树开始进行了对应的销毁了:

这里我们发现了他是乱码的。但是不能否定的是这个对象是进行了对应的析构的。

乱码问题:

看见乱码的问题,不要想就是对应的编码不一致, 一般QT 都是utf-8的编码,而我们的计算机一般都是GBK编码的所以它的编码是不统一的。 在linux中一般使用的编码是utf-8。所以在liunx是不会出现乱码的。 那么我尝试的寻找了一下是不能更换编码的(如果有欢迎道友们进行交流)。

所以这时候我们就要使用qDebug来进行对应的打印

qDebug的使用

头文件<QDebug>

我们发现他们没有出现乱码的行为了。qDebug是一个宏这个宏里封装了对应的QDebug对象。

他会自动识别转换编码。

相比较cout,qDebug还有一个好处:

在运行是调试日志会统一的进行关闭的。

相关推荐
wjs20241 小时前
jQuery Mobile 触摸事件详解
开发语言
kyriewen111 小时前
你的前端滤镜慢得像PPT?用Rust+WebAssembly,一秒处理4K图
开发语言·前端·javascript·设计模式·rust·ecmascript·powerpoint
小杍随笔1 小时前
【Tauri 2 + Rust 配置 WebView2 缓存数据存储到安装目录】
开发语言·后端·rust·tauri
人道领域1 小时前
【LeetCode刷题日记】二叉树层序遍历完全指南:从基础到LeetCode实战一篇搞定BFS模板,秒杀4道经典面试题
java·开发语言·数据结构·leetcode·面试·二叉树
孬甭_1 小时前
预处理详解
c语言·开发语言
CSCN新手听安2 小时前
【Qt】系统相关(二)鼠标事件的处理,鼠标的按下,释放,双击,移动,滚轮滚动事件的处理
开发语言·c++·qt
yqcoder2 小时前
JavaScript 深拷贝:如何彻底切断引用关联?
开发语言·前端·javascript
知识分享小能手2 小时前
R语言入门学习教程,从入门到精通,初识R语言(1)
开发语言·学习·r语言
代码羊羊3 小时前
Rust 迭代器完全通俗易懂指南(零基础全覆盖)
java·开发语言·rust