前言
Qt中引入对象树的概念是用于管理对象的释放,它还提供了一种组织和结构化对象的方式,使得对象之间的层次关系更加清晰。因为当我们在堆上创建很多对象时,总不能一个一个的释放吧?于是引入对象树的概念,当我们为一个对象指定好父对象时通过父对象来管理子对象的内存释放。
正文
在 Qt 中,对象树(Object Tree)是通过 QObject
的父子关系来实现的一种对象层次结构管理方式。所有继承自 QObject
的类都可以参与对象树的构建。每个 QObject
对象可以有一个父对象(parent
),并且可以拥有多个子对象(children
)。当一个对象被销毁时,Qt 会自动销毁它的所有子对象。这种层次结构确保了对象的生命周期管理更加简单和可靠。
在帮助文档中我们可以看到 QObject
中的children()
函数
const QObjectList &QObject::children() const
是 QObject
类的一个成员函数,它用于获取一个对象的所有子对象。
QObject::children()
函数
函数声明
const QObjectList &children() const;
返回值
- 返回值类型:
const QObjectList &
QObjectList
是一个类型别名,定义为QList<QObject*>
,即QObject
指针的列表。
- 返回值:这个函数返回当前对象的所有子对象的列表。子对象是通过
QObject
的父子关系进行管理的,父对象会拥有一个QObjectList
,其中包含它所有的直接子对象。
特点和行为
-
子对象列表的顺序:
- 列表中的第一个元素是第一个添加的子对象,最后一个元素是最后添加的子对象。即,新的子对象会被追加到列表的末尾。
- 注意,
QWidget
的子对象列表顺序会受到显示层次的影响:如果一个子对象被提升(raise)到最上层,它会成为列表中的最后一个对象;如果一个子对象被降低(lower),它会成为列表中的第一个对象。这是因为QWidget
类(QObject
的子类)还涉及到界面层次的管理。
-
对象的顺序管理:
- 对于
QWidget
这样的可视化组件,调用raise()
或lower()
函数会影响其在子对象列表中的位置。这是为了确保界面显示的层次关系与对象列表的顺序一致。
- 对于
相关函数
findChild()
:用于查找单个子对象,可以根据对象的类型和名称来查找。QObject *findChild(const QString &name, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const;
findChildren()
:用于查找所有符合条件的子对象,返回一个QObjectList
。QObjectList findChildren(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const;
parent()
:返回当前对象的父对象。QObject *parent() const;
setParent()
:设置当前对象的父对象,并自动调整对象树中的层次关系。void setParent(QObject *parent);
示例代码
下面是一个简单的示例,演示了如何使用 children()
方法获取一个 QObject
对象的所有子对象:
#include <QObject>
#include <QDebug>
class MyObject : public QObject {
Q_OBJECT
public:
MyObject(QObject *parent = nullptr) : QObject(parent) {}
};
int main() {
// 创建父对象
QObject *parentObject = new QObject();
// 创建子对象,并指定父对象
MyObject *child1 = new MyObject(parentObject);
MyObject *child2 = new MyObject(parentObject);
// 获取父对象的所有子对象
const QObjectList &children = parentObject->children();
for (QObject *child : children) {
qDebug() << "Child object:" << child;
}
// 删除父对象,子对象将自动被删除
delete parentObject;
return 0;
}
在这个例子中,我们创建了一个 QObject
父对象,并添加了两个 MyObject
子对象。然后,通过 children()
方法获取父对象的所有子对象,并输出这些子对象的信息。最后,当父对象被删除时,子对象会自动被销毁。
对象树的限制
尽管对象树非常有用,但也有一些需要注意的地方:
-
内存管理:在某些情况下,你可能不希望子对象随着父对象销毁,这时需要小心设置父子关系。
-
层次过深:如果对象树层次过深,可能会导致代码复杂性增加,难以管理。
-
程序崩溃:如果一个对象被释放两次,则可能会到这程序崩溃
例子:都知道在c++中对象的析构与创建的顺序是相反的,当我们为一个对象指定好父对象而且该子对象先于父对象创建,当父对象析构时子对象会被析构两次
include "widget.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
// 创建一个对象a,
QApplication a(argc, argv);
//子对象先于父对象创建
QPushButton btn;
//创建父对象
Widget w;
//为btn指定父对象
btn.setParent(&w);
w.show();
//调用exec方法
return a.exec();
}
运行结果
解决办法:
子对象后于父对象创建或者不指定父对象自己管理内存释放
总结
Qt 的对象树通过父子关系实现了对象的层次管理和生命周期自动化管理,极大地方便了开发者管理复杂对象结构,尤其是在 GUI 应用程序中。理解和有效使用对象树是开发 Qt 应用程序的重要技能。