概述
QObject
在对象树中组织自己。当您创建带有另一个对象作为父对象的QObject时,它会添加到父对象的children()
列表中,并在父对象被删除时被删除。事实证明,这种方法非常适合GUI的需要。例如,QShortcut(键盘快捷方式)是相关窗口的子级,因此,当用户关闭该窗口时,快捷方式也会被删除。
QQuickItem
是Qt Quick模块的基本可视元素,它继承自QObject
,但是其可视父对象的概念不同于QObject
父对象的概念。项的视觉父项不一定与它的对象父项相同。有关更多详细信息,请参见Qt Quick中的概念-可视化父类。
QWidget
是Qt Widgets模块的基本类,它扩展了父子关系。自不见通常也会称为子部件,也就是说,它显示在其父部件的坐标系统中,并被其父部件的边界以图形方式剪切。例如,当应用程序在消息框关闭后删除它时,消息框的按钮和标签也会被删除,正如我们所希望的那样,因为按钮和标签是消息框的子元素。
您也可以自己删除子对象,它们将从自己的父对象中删除。比如,当用户删除一个工具栏时,它可能导致应用程序删除它的一个QToolBar对象
,在这种情况下,工具栏的QMainWindow父类将检测到更改并相应的重新配置它的屏幕空间。
当应用程序外观或行为异常时,调试功能QObject :: dumpObjectTree()
和QObject :: dumpObjectInfo()
通常很有用。
QObject的构建/销毁顺序
当在堆上创建QObject
时(即使用new创建),可以用它们的任何顺序构建树,之后,可以用任何顺序销毁树中的对象。当删除树中的任何QObject时,如果该对象有父对象,析构函数将自动从父对象中删除该对象。如果对象有子对象,析构函数会自动删除每个子对象。无论销毁的顺序如何,QObject都不会被删除两次。
当在堆上创建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随后超出作用域时,它的析构函数将再次被调用,这一次是正确的,但损害已经造成。