《Qt MOOC系列教程》第二章第四节:父子关系

1. 对象树

QObject将自己组织在对象树中。当您以一个对象作为父对象创建QObject时,该对象将被添加到父对象的children()列表中,并在父对象被删除时删除。事实证明,这种方法非常适合GUI编程。例如,QShortcut(键盘快捷方式)是相关窗口的子对象,因此当用户关闭该窗口时,快捷方式也会被删除。

QQuickItem是Qt Quick模块的基本可视化元素,我们将在本课程的后面部分讨论它,它继承于QObject,但有一个可视化父元素的概念,它与QObject父元素不同。一个可视化元素不一定与它的父对象元素相同。有关更多详细信息,请参见Concepts - Visual Parent in Qt Quick

您还可以自己删除子对象,它们将从父对象中删除自己。例如,当用户删除一个工具栏时,需要应用程序删除它的QToolBar对象,在这种情况下,工具栏的父对象QMainWindow会检测到变化并重现刷新界面。

2. 对象和指针的持久性

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

QObject在栈上创建时,表现的行为与上述类似。正常情况下,销毁的顺序仍然不成问题。考虑以下代码段:

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

父对象(window)和子对象(quit)都是QObject,因为QPushButton继承QWidget, QWidget继承QObject。上面代码是正确的: quit的析构函数不会被调用两次,因为C++语言标准(ISO/IEC 14882:2003)规定对象的析构函数调用顺序与其构造函数顺序相反。因此,子对象quit的析构函数首先被调用,它在window的析构函数调用之前从父对象window中删除了自己。

但是现在考虑一下,如果我们更改了构造的顺序会发生什么,如下面的第二个代码段所示:

int main()
{
    QPushButton quit("Quit");
    QWidget window;

    quit.setParent(&window);
    ...
}

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

总结一下:

  • 对象树可以以任意的顺序构造
  • 对象树可以以任意的顺序销毁
  • 如果对象拥有父对象则该对象首先从父对象中移除
  • 如果对象拥有子对象则首先删除所有子对象
  • 对象不会被删除两次

请注意,父子关系与继承不是一回事。

3. 悬浮指针问题

对象树不能解决悬浮指针问题,但是QPointerQObject提供了一个受保护的指针。当使用的对象被销毁时,指针将被设置为0。很容易将受保护的指针和普通指针混合使用。受保护的指针将自动转换为指针类型。

Qt对象也可以在销毁之前通知观察者。

Source

获取更多信息,请关注作者公众号:程序员练兵场
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值