对象树与所有权

概述

QObjects 对象以对象树的形式组织起来。当您创建一个以另一个对象为父对象的 时,它会被添加到父对象的 () 列表中,并在父对象删除时被删除。事实证明,这种方法非常适合图形用户界面对象的需要。例如, (键盘快捷键)是相关窗口的子对象,因此当用户关闭该窗口时,快捷键也会被删除。QObject children QShortcut

QQuickItem Qt Quick 模块的基本可视元素--"...... "继承自 ,但它的QObject可视父元素概念与 的QObject 元素概念不同。项目的可视化父级不一定与其对象父级相同。详情请参阅 Qt Quick 中的概念 - 视觉父级

QWidget子类是Qt Widgets 模块的基本类,它扩展了父子关系。子部件通常也会成为子部件,即在父部件的坐标系中显示,并在图形上被父部件的边界剪切。例如,当应用程序在关闭消息框后将其删除时,消息框的按钮和标签也会被删除,这正是我们所希望的,因为按钮和标签都是消息框的子部件。

你也可以自己删除子对象,它们也会从父对象中删除。例如,当用户删除工具栏时,应用程序可能会删除其QToolBar 对象,在这种情况下,工具栏的QMainWindow 父对象会检测到这一变化,并相应地重新配置其屏幕空间。

当应用程序出现异常外观或行为时,调试函数QObject::dumpObjectTree() 和QObject::dumpObjectInfo() 通常非常有用。

QObject 的构造/销毁顺序

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

QObjects 在堆栈上创建时,同样的行为也适用。通常情况下,销毁顺序不会产生问题。请看下面的代码段:

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

父程序window 和子程序quit 都是QObjects ,因为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 退出作用域后,它的析构函数再次被调用,这次是正确的,但破坏已经造成。

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.