Qt物件樹和擁有權

2021-07-23 17:31:14 字數 4252 閱讀 8180

1、qt智慧型指標和qobject物件樹系統(父子系統)結合使用出現的問題----

2、qt學習筆記(六)之簡析物件樹----

一、物件模型

標準c++物件模型可以在執行時非常有效的支援物件正規化(object paradigm),但是它的靜態特性在一些問題領域中不夠靈活。圖形使用者介面程式設計不僅需要執行時的高效性,還需要高度的靈活性。為此,qt在標準c++物件模型的基礎上新增了一些特性,形成了自己的物件模型。這些特性有:

qt的這些特性都是在遵循標準c++規範內實現的,使用這些特性都必須要繼承自qobject類。其中物件通訊機制和動態屬性系統,還需要元物件系統(meta-objectsystem)的支援。關於物件模型的介紹,大家可以在幫助中檢視object model關鍵字。

二、元物件系統

qt中的元物件系統(meta-object system)提供了物件間通訊的訊號和槽機制、執行時型別資訊和動態屬性系統。元物件系統是基於以下三個條件的:

其中moc工具讀取乙個c++原始檔,如果它發現乙個或者多個類的宣告中包含有q_object巨集,便會另外建立乙個c++原始檔(就是在專案目錄中的debug目錄下看到的以moc開頭的c++原始檔),其中包含了為每乙個類生成的元物件**。這些產生的原始檔或者被包含進類的原始檔中,或者和類的實現同時進行編譯和鏈結。

元物件系統主要是為了實現訊號和槽機制才被引入的,不過除了訊號和槽機制以外,元物件系統還提供了其他一些特性:

除了這些特性外,還可以

使用qobject_cast()函式來對qobject類進行動態型別轉換,這個函式的功能類似於標準c++中的dynamic_cast()函式,但它不再需要rtti的支援。這個函式嘗試將它的引數轉換為尖括號中的型別的指標,如果是正確的型別則返回乙個非零的指標,如果型別不相容則返回0。例如:

qobject *obj = new mywidget;

qwidget *widget = qobject_cast(obj);

訊號和槽機制是qt的核心內容,而訊號和槽機制必須依賴於元物件系統,所以它是qt

中很關鍵的內容。關於元物件系統的知識,可以在qt

中檢視the meta-object system

關鍵字。

三、物件樹與擁有權

qt中使用物件樹(object tree)來組織和管理所有的qobject類及其子類的物件。當建立乙個qobject時,如果使用了其他的物件作為其父物件(parent),那麼這個qobject就會被新增到父物件的children()列表中,這樣當父物件被銷毀時,這個qobject也會被銷毀。實踐表明,這個機制非常適合於管理gui物件。例如,乙個qshortcut(鍵盤快捷鍵)物件是相應視窗的乙個子物件,所以當使用者關閉了這個視窗時,這個快捷鍵也可以被銷毀。

qwidget

作為能夠在螢幕上顯示的所有部件的基類,擴充套件了物件間的父子關係。乙個子物件一般也就是乙個子部件,因為它們要顯示在父部件的區域之中。例如,當關閉乙個訊息對話方塊(message box

)後要銷毀它時,訊息對話方塊中的按鈕和標籤也會被銷毀,這也正是我們所希望的,因為按鈕和標籤是訊息對話方塊的子部件。當然,我們也可以自己來銷毀乙個子物件。關於這一部分的內容,大家可以在幫助索引中檢視object trees &ownership

關鍵字。

在前面的qt

程式設計中我們應該看到過很多使用new

來建立乙個部件,但是卻沒有使用delete

來進行釋放的問題。這裡再來研究一下這個問題。

新建qt gui

應用,專案名稱為「myownership

」,基類選擇qwidget

,然後類名保持「widget

」不變。完成後向專案中新增新檔案,模板選擇c++ class

,類名為「mybutton

」,基類為「qpushbutton

」,型別資訊選擇「繼承自qwidget

」。新增完檔案後在mybutton.h

檔案中新增析構函式的宣告:

~mybutton();

然後到mybutton.cpp檔案中新增標頭檔案#include 並定義析構函式:

mybutton

::~mybutton()

這樣當mybutton

的物件被銷毀時,就會輸出相應的資訊。這裡定義析構函式,只是為了更清楚的看到部件的銷毀過程,其實一般在構建新類時不需要實現析構函式。下面在widget.cpp

檔案中進行更改,新增標頭檔案:

#include

"mybutton.h"

#include

在建構函式中新增**:

mybutton

*button

=new

mybutton

(this

); // 

建立按鈕部件,指定

widget

為父部件

button->

settext(tr("button"));

更改析構函式:

widget

::~widget()

widget

類的析構函式中預設的已經有了銷毀ui

的語句,這裡又新增了輸出語句。當widget

視窗被銷毀時,將輸出資訊。下面執行程式,然後關閉視窗,在qtcreator

的應用程式輸出欄中的輸出資訊為:

delete widget

delete button

可以看到,當關閉視窗後,因為該視窗是頂層視窗,所以應用程式要銷毀該視窗部件(如果不是頂層視窗,那麼關閉時只是隱藏,不會被銷毀),而當視窗部件銷毀時會自動銷毀其子部件。這也就是為什麼在qt

中經常只看到new

操作而看不到delete

操作的原因。再來看一下main.cpp

檔案,其中

widget

物件是建立在棧上的:

widget

w;w. show();

這樣對於物件w,在關閉程式時會被自動銷毀。而對於widget中的部件,如果是在堆上建立(使用new操作符),那麼只要指定widget為其父視窗就可以了,也不需要進行delete操作。整個應用程式關閉時,會去銷毀w物件,而此時又會自動銷毀它的所有子部件,這些都是qt的物件樹所完成的。

所以,對於規範的qt程式,我們要在main()函式中將主視窗部件建立在棧上,例如「widget w;」,而不要在堆上進行建立(使用new操作符)。對於其他視窗部件,可以使用new操作符在堆上進行建立,不過一定要指定其父部件,這樣就不需要再使用delete操作符來銷毀該物件了。

還有一種重定義父部件(reparented

)的情況,例如,將乙個包含其他部件的布局管理器應用到視窗上,那麼該布局管理器和其中的所有部件都會自動將它們的父部件轉換為該視窗部件。在widget.cpp

檔案中新增標頭檔案

#include

,然後在建構函式中繼續新增**:

mybutton

*button2

=new

mybutton

;mybutton

*button3

=new

mybutton

;qhboxlayout

*layout

=new

qhboxlayout

;layout->

addwidget(button2);

layout->

addwidget(button3);

setlayout(layout);      // 

在該視窗中使用布局管理器

這裡建立了兩個mybutton

和乙個水平布局管理器,但是並沒有指定它們的父部件,現在各個部件的擁有權(ownership

)不是很清楚。但是當使用布局管理器來管理這兩個按鈕,並且在視窗中使用這個布局管理器後,這兩個按鈕和水平布局管理器都將重定義父部件而成為視窗widget

的子部件。可以使用children()

函式來獲取乙個部件的所有子部件的列表,例如在建構函式中再新增如下**:

qdebug() << children();    

// 輸出所有子部件的列表

這時大家可以執行一下程式,檢視應用程式輸出欄中的資訊,然後根據自己的想法更改一下程式,來進一步體會qt

中物件樹的概念。

四、總結

qt中的物件樹很好地解決了父子部件的關係,對於gui

程式設計是十分方便的,在建立部件時我們只需要關注它的父部件,這樣就不用再考慮其銷毀問題了。下一節,我們將講解qt中的訊號和槽的內容。

分類: 

qt學習筆記

QT中的物件樹與物件擁有權

qobjects以物件樹組織它們自己。當你建立乙個qobject以另乙個物件作為其父物件時,這個qobject被加入到其父物件的children 列表中,當父物件對被刪除時,其子物件也會被刪除。實踐表明這種組織方式非常適合gui物件的特點與需要。舉例來說,乙個qshortcut 鍵盤快捷鍵 是其相關...

智慧型指標擁有權問題

1.深拷貝問題在於對於乙個指向基類的指標採用深拷貝或者物件本身的拷貝函式不確定的時候,問題變的視乎極難處理。2.臨寫拷貝同樣也存在問題,它對呼叫者提出了比較高的要求,因為指標本身不知道是否執行臨寫拷貝。3.引用計數是好,可以這也有多個策略。a.為了指向引用計數段,指標大小翻倍,會導致空間佔用量爬公升...

Qt之物件樹與所有權

qobjects在乙個物件樹中組織他們自己。當建立乙個qobject時,如果使用了其他物件作為其父物件,那麼,它就會被新增到父物件的children 列表中。這樣一來,當父物件被銷毀時,這個qobject也會被銷毀。事實表明,這個機制非常適合於管理gui物件。例如 乙個qshortcut 鍵盤快捷鍵...