Qt文档阅读笔记-Object Trees Ownership解析与实例(为何某些程序在被关闭的时候会崩溃)
目錄
官方解析
Construction/Destruction Order of QObjects
博主栗子
繼承里面構(gòu)造函數(shù)與析構(gòu)函數(shù)的順序
在Qt中,object trees里面的創(chuàng)建與析構(gòu)
【重要實(shí)例】在棧區(qū)創(chuàng)建的時(shí)候,就有問(wèn)題了
官方解析
每一個(gè)QObject都有自己的一顆對(duì)象樹。當(dāng)你創(chuàng)建一個(gè)QObject對(duì)象,并且另一個(gè)對(duì)象作為他的parent的時(shí)候,這個(gè)新創(chuàng)建的對(duì)象就會(huì)被添加到父類的children()list中,當(dāng)parent被刪除的時(shí)候他的children都會(huì)被刪除。這種方式對(duì)GUI對(duì)象是十分有用的【從這里可以知道,當(dāng)要對(duì)GUI進(jìn)行操作的時(shí)候,優(yōu)先考慮設(shè)置parent,因?yàn)榻缑姹粍h除的時(shí)候,控件也會(huì)被刪除,其他成員得自己去delete】。舉個(gè)栗子,QShortcut類創(chuàng)建的對(duì)象是某一個(gè)窗口的child,當(dāng)這個(gè)窗口被關(guān)閉后,這個(gè)類的對(duì)象也會(huì)被Delete掉。
QQuickItem這個(gè)玩意是Quick module的最基礎(chǔ)的視覺(jué)元素,并且他也是QObject的派生類,不過(guò),visual parent與傳統(tǒng)控件里面的QObject parent概念不同。一個(gè)item的visual parent不一定與object parent相同。相關(guān)細(xì)節(jié)查看Concepts - Visual Parent in Qt Quick。
QWidget是最基礎(chǔ)的Qt Widgets module 類,這個(gè)類擴(kuò)展了parent-child的關(guān)系。他的child通常可以看做他的子部件,子窗口等。QWidget里面的這些child顯示于他的parent坐標(biāo)系并且他的形狀受他parent的邊界的影響【一般情況下是這樣,但如果有布局,就會(huì)受到布局的影響】。舉個(gè)栗子,當(dāng)這個(gè)程序被關(guān)閉后,填出一個(gè)delete的Messagebox,這個(gè)Messagebox的按鈕和標(biāo)簽都會(huì)被刪除,當(dāng)然這是你設(shè)置了parent的情況下才會(huì),設(shè)置了才會(huì)刪除,沒(méi)設(shè)置就不會(huì)被刪除。
你可以自己手動(dòng)delete某個(gè)對(duì)象樹中的子對(duì)象,如果刪除掉,他也會(huì)自動(dòng)從他的parent中的child中刪除,舉個(gè)栗子,當(dāng)移除toolbar后會(huì)導(dǎo)致應(yīng)用程序刪除QToolBar這個(gè)類對(duì)應(yīng)的對(duì)象,在這種情況下QMainWindow將檢查并且改變程序的屏幕位置。
當(dāng)一個(gè)程序的外觀或行為異常的時(shí)候,調(diào)試功能QObject::dumpObjectTree()和QObject::dumpObjectInfo()將十分有效。
Construction/Destruction Order of QObjects
當(dāng)在堆區(qū)創(chuàng)建了許多QObjects對(duì)象的時(shí)候,對(duì)象樹會(huì)以任意的順序被創(chuàng)建,之后他們會(huì)以任意的順序銷毀。如果這個(gè)對(duì)象有parent,析構(gòu)的時(shí)候就會(huì)自動(dòng)從他的parent中移除。如果這個(gè)對(duì)象有children,析構(gòu)這個(gè)對(duì)象的時(shí)候他會(huì)自動(dòng)析構(gòu)他的每一個(gè)child,無(wú)論銷毀順序如何,他都不會(huì)調(diào)用兩次。
當(dāng)對(duì)象們?cè)跅^(qū)創(chuàng)建的時(shí)候,上述的行文同樣適合,通常析構(gòu)的順序不會(huì)帶來(lái)什么問(wèn)題。,可以參考下如下的代碼段:
int main(){QWidget window;QPushButton quit("Quit", &window);...}
parent和child都是QObject對(duì)象,因?yàn)镼PushButton繼承于QWidget,而QWidget繼承于QObject。這個(gè)代碼是正確的:在quit被銷毀的時(shí)候不會(huì)調(diào)用兩次,因?yàn)镃++11指出創(chuàng)建對(duì)象的順序,與析構(gòu)的順序相反。因此當(dāng)child被析構(gòu)后quit先會(huì)被析構(gòu),然后從他的parent里面把他給移除,然后再析構(gòu)這個(gè)windows對(duì)象。
現(xiàn)在考慮下交換構(gòu)造順序,將發(fā)送什么問(wèn)題,如下面這段代碼:
int main(){QPushButton quit("Quit");QWidget window;quit.setParent(&window);...}
在這種情況下,析構(gòu)就會(huì)導(dǎo)致一個(gè)問(wèn)題,quit的parent先會(huì)被調(diào)用,因?yàn)樗蟊粍?chuàng)建。然后再銷毀他的子對(duì)象quit,這樣做是不準(zhǔn)確的,因?yàn)閝uit是本地變量。當(dāng)quit被銷毀后,他的析構(gòu)函數(shù)又被調(diào)用了一次,這一次才正常的調(diào)用,不過(guò)這可能會(huì)導(dǎo)致程序的崩潰!
?
博主栗子
?
繼承里面構(gòu)造函數(shù)與析構(gòu)函數(shù)的順序
運(yùn)行截圖如下:
源碼如下:
main.cpp
#include <iostream> using namespace std;class Base { public:virtual void print() {cout << "Base print called!\n";}Base() {cout << "Base construction called!\n";}~Base() {cout << "Base deconstruction called!\n";} };class Child1 :public Base { public:void print() {cout << "Child1 print called!\n";Base::print();}Child1() {cout << "Child1 construction called!\n";}~Child1() {cout << "Child1 construction called!\n";} };class Child2 :public Base { public:void print() {cout << "Child2 print called!\n";}Child2() {cout << "Child2 construction called!\n";}~Child2() {cout << "Child2 deconstruction called!\n";} };void main() {Child1 *child1 = new Child1;delete child1;getchar(); }?
在Qt中,object trees里面的創(chuàng)建與析構(gòu)
運(yùn)行截圖如下:
源碼如下:
democlass.h
#ifndef DEMOCLASS_H #define DEMOCLASS_H#include <QObject>class Base : public QObject {//Q_OBJECT to use object tree without singals and slots. so we needn't Q_OBJECT public:Base(QObject *parent = 0);~Base(); };class Child:public QObject{ public:Child(QObject *parent=0);~Child(); };class OtherBase:public QObject{ public:OtherBase(QObject *parent=0);~OtherBase(); };#endif // DEMOCLASS_Hdemoclass.cpp
#include "democlass.h" #include <QDebug>Base::Base(QObject *parent) : QObject(parent) {qDebug()<<"Base construction called!"; }Base::~Base() {qDebug()<<"Base deconstruction called!"; }Child::Child(QObject *parent):QObject(parent) {qDebug()<<"Child construction called!"; }Child::~Child() {qDebug()<<"child deconstruction called!"; }OtherBase::OtherBase(QObject *parent):QObject(parent) {qDebug()<<"OtherBase construction called!"; }OtherBase::~OtherBase() {qDebug()<<"otherBase deconstruction called!"; }main.cpp
#include <QDebug> #include <QApplication> #include "democlass.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Base *base=new Base;Child *child_1=new Child(base);OtherBase *otherBase_1=new OtherBase(base);OtherBase *otherBase_2=new OtherBase(base);Child *child_2=new Child(child_1);base->dumpObjectTree();delete base;return a.exec(); }?
【重要實(shí)例】在棧區(qū)創(chuàng)建的時(shí)候,就有問(wèn)題了
運(yùn)行截圖如下:
源碼如下:
democlass.h
同上
democlass.cpp
同上
main.cpp
#include <QDebug> #include <QApplication> #include "democlass.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);{Child child;Base base;child.setParent(&base);qDebug()<<"Prepare deconstruction";}return a.exec(); }這個(gè)原因是,只有手動(dòng)刪除的時(shí)候(在堆區(qū)創(chuàng)建的才能手動(dòng)刪除),才會(huì)把parent中的對(duì)應(yīng)自己的child刪除,在棧中都是系統(tǒng)調(diào)用,沒(méi)有這種機(jī)制!!,這樣就會(huì)調(diào)用2次Delete
所以這種代碼,正確的改法如下:
#include <QDebug> #include <QApplication> #include "democlass.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);{Base base;Child child;child.setParent(&base);qDebug()<<"Prepare deconstruction";}return a.exec(); }運(yùn)行截圖如下:
總結(jié)
以上是生活随笔為你收集整理的Qt文档阅读笔记-Object Trees Ownership解析与实例(为何某些程序在被关闭的时候会崩溃)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C++与QML交互(信号与槽通知QML,
- 下一篇: Qt工作笔记-图形视图框架中的分组,以及