QObject对象树 ObjectTree

       不知道刚接触Qt的小伙伴有没有这样的疑问,在Qt中new出来的对象没有手动delete来释放,难道Qt中不需要释放?Qt还是基于C++的框架,肯定还是需要delete的,答案就是Qt的对象树模型。通过对象树可以在父对象被析构的时候,自动地析构子对象。当然要支持对象树,需要继承QObject或QObject的子类。我们现在就来看看是怎么实现对象树的。

       QObject有一个成员d_ptr,它的定义如图1所示(参看qobject.h):

图1

 QObjectData有一个成员children来保存子对象,它的定义如图2所示(参看qobject.h):

图2

        QObjectList其实就是QList<QObject*>,在qobject.h中可以看到typedef QList<QObject*> QObjectList。当QObject被释放的时候就会把children中的子对象一一的delete掉。在QObject的析构函数中会有这么一段代码,如图3所示:

图3

       d是一个指针(关于Qt中D指针和Q指针,以后再讲),他的类型是QObjectPrivate。而QObjectPrivate是继承QObjectData,参看qobject_p.h。deleteChildrend的实现如图4所示(参看qobject.cpp):

图4

       现在我清楚了它的释放流程,现在剩下的就是Qt怎么把子对象放到children列表中,这就要从QObject的构造函数和成员函数setParent函数说起了。QObject的构造函数如图5所示(参看qobject.h):

图5

     可以看到在构造函数参数中有一个parent,如果不为空的时候,就是把该对象保存到parent的children列表中,如图6所示(参看qobject.cpp):

图6

     在setParent中会调用QObjectPrivate::setParent_helper,它的实现如图7所示(参看qobject.cpp):

图7

       首先需要在o的原来的父对象的children列表中把o删除,如果不删除的话,这样就有2个父对象都保存了o的指针,这样在析构的时候就会出现o被delete 2次的情况。然后再把o加到新的父对象的children列表中。通过上面的方式就把子对象的指针保存到了父对象的children中了。值得注意的是,如果在构造时设置父对象为 nullptr,那么当前对象不会有父对象存在,Qt 也不会自动释放该对象,除非超出作用域导致析构函数被调用,或者用户在恰当时机使用 delete 操作符或者使用 QObject::deleteLater 方法。

        那如果我们先把子对象释放了会发生什么,会不会出现父对象再析构的时候再一次的释放该对象?答案是不会的,原因就在QObject对象在析构的时候会把自己从父对象的children列表中自动的删除掉,如图8所示:

图8

setParent_helper是实现参看图7,他首先就是从父对象的children列表中删除。

如果要获取子对象,可以通过如图9所示的函数获取

图9

其中children获取所有的子对象,findChild和findChildren是模板函数,可以获取特定类型的子对象。如果获取QPushButton类型的子对象

QList<QPushButton *> allPButtons = parentWidget.findChildren<QPushButton *>();

        使用对象树存在的一个问题,我们都知道C++中规定了析构顺序应该按照其创建顺序的相反过程,也就是说先创建的对象会后析构。我们看一段代码,如图10所示:

图10

        如果关闭窗口会导致程序异常结束,为什么会出现这样的情况?各位聪明小伙伴根据前面的知识应该能想出来,如果大家有什么不明白的,可以在评论区告诉我。为了避免这个问题我们可以这么做:

  1. 先创建父对象再创建子类对象,并且在创建子对象时就指定父对象;
  2. 尽量在堆上创建子对象;

       如果类型不是QObject或QObject继承类型怎么管理,这个就可以使用智能指针了,关于智能指针(QScopedPointer和QSharedPointer)的使用会在后面的文章讲解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小王哥编程

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

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

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

打赏作者

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

抵扣说明:

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

余额充值