Spec-Zone.ru › Qt 5.15

Деревья объектов и владение

Обзор

QObjects организуются в деревья объектов. Когда вы создаете QObject с другим объектом в качестве родителя, он добавляется в список children() родителя и удаляется при удалении родителя. Такой подход прекрасно подходит для GUI-объектов. Например, QShortcut (горячая клавиша) является дочерним элементом соответствующего окна, поэтому при закрытии пользователя этого окна, горячая клавиша также удаляется.

QQuickItem, базовый визуальный элемент модуля Qt Quick, наследует от QObject, но имеет понятие визуального родителя, отличного от родителя QObject. Визуальный родитель элемента необязательно совпадает с его родительским объектом. Подробнее см. Концепции — Визуальный родитель в Qt Quick.

QWidget, базовый класс модуля Qt Widgets, расширяет отношения родитель-потомок. Дочерний элемент обычно также становится дочерним виджетом, т.е. отображается в системе координат своего родителя и графически обрезается границами своего родителя. Например, когда приложение удаляет сообщение после его закрытия, кнопки и метка сообщения также удаляются, как и ожидалось, потому что кнопки и метка являются дочерними элементами сообщения.

Вы также можете сами удалить дочерние объекты, и они удалят себя из своих родителей. Например, при удалении пользователем панели инструментов это может привести к удалению приложения одного из его объектов QToolBar, в этом случае родитель QMainWindow панели инструментов обнаружит изменение и соответствующим образом переконфигурирует пространство экрана.

Функции отладки QObject::dumpObjectTree() и QObject::dumpObjectInfo() часто полезны, когда приложение выглядит или ведет себя странно.

Порядок построения/разрушения QObjects

Когда 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 выходит из области видимости, его деструктор вызывается снова, на этот раз правильно, но вред уже нанесен.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/archives/qt-5.11/objecttrees.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API