對象樹 & 所有權

概述

QObjects 在對象樹中組織自身。當創建 QObject 采用另一對象作為父級,它被添加到父級的 children() 列錶,和被刪除當刪除父級時。事實證明,這種方式非常適閤 GUI 對象的需要。例如, QShortcut (鍵盤快捷方式) 是相關窗口的子級,因此當用戶關閉該窗口時,快捷方式也會被刪除。

QQuickItem ,Qt Quick 模塊的基本視覺元素,繼承自 QObject ,但擁有概念化的 視覺父級 其不同於 QObject parent 。項的視覺父項不必與其對象父項相同。見 概念 - Qt Quick 中的視覺父級 瞭解更多細節。

QWidget , the fundamental class of the Qt Widgets module, extends the parent-child relationship. A child normally also becomes a child widget, i.e. it is displayed in its parent's coordinate system and is graphically clipped by its parent's boundaries. For example, when the application deletes a message box after it has been closed, the message box's buttons and label are also deleted, just as we'd want, because the buttons and label are children of the message box.

You can also delete child objects yourself, and they will remove themselves from their parents. For example, when the user removes a toolbar it may lead to the application deleting one of its QToolBar objects, in which case the tool bar's QMainWindow parent would detect the change and reconfigure its screen space accordingly.

調試函數 QObject::dumpObjectTree () 和 QObject::dumpObjectInfo () are often useful when an application looks or acts strangely.

QObject 的構造/銷毀次序

QObjects are created on the heap (i.e., created with new ), a tree can be constructed from them in any order, and later, the objects in the tree can be destroyed in any order. When any QObject in the tree is deleted, if the object has a parent, the destructor automatically removes the object from its parent. If the object has children, the destructor automatically deletes each child. No QObject is deleted twice, regardless of the order of destruction.

QObjects are created on the stack, the same behavior applies. Normally, the order of destruction still doesn't present a problem. Consider the following snippet:

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

父級, window ,和子級, quit ,兩者是 QObjects 因為 QPushButton 繼承 QWidget ,和 QWidget 繼承 QObject . This code is correct: the destructor of quit is not called twice because the C++ language standard (ISO/IEC 14882:2003) specifies that destructors of local objects are called in the reverse order of their constructors. Therefore, the destructor of the child, quit , is called first, and it removes itself from its parent, window , before the destructor of window 被調用。

But now consider what happens if we swap the order of construction, as shown in this second snippet:

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

In this case, the order of destruction causes a problem. The parent's destructor is called first because it was created last. It then calls the destructor of its child, quit , which is incorrect because quit is a local variable. When quit subsequently goes out of scope, its destructor is called again, this time correctly, but the damage has already been done.