2011-06-03 37 views
14

在Qt中,我可以通過編寫將子窗口小部件嵌入其父項中,還是必須使用new創建它們?Qt:子對象可以在他們的父對象中組成嗎?

class MyWindow : public QMainWindow 
{ 
    ... 
private: 
    QPushButton myButton; 
} 

MyWindow::MyWindow() 
: mybutton("Do Something", this) 
{ 
    ... 
} 

文檔說,當它的父被破壞從QObject派生的任何對象會自動銷燬;這意味着致電delete,在上面的例子中會崩潰。

我必須使用以下嗎?

QPushButton* myButton; 

myButton = new QPushButton("Do Something", this); 

編輯

的答案是多種多樣的,基本上可以歸結爲三種可能性:

  • ,構圖OK。 Qt可以找出對象是如何分配和僅delete堆中分配的對象(這是如何工作的?)
  • ,成分是好的,但不指定父,因爲父原本叫delete上該對象(但是不會將無母公司的小部件變成頂級窗口?)
  • ,小部件總是需要堆分配。

哪一個是正確的?

回答

7

當特定對象的刪除序列開始時,非靜態非堆成員變量被刪除。只有當所有成員都被刪除後,它纔會進入基類的析構函數。因此,在調用〜QMainWindow()之前,QPushButton myButton成員將被刪除。從QObject文檔:「如果我們刪除其父對象之前的子對象,Qt會自動從父對象的子對象列表中刪除該對象」。因此不會發生崩潰。

+1

你的回答幾乎是正確的,但銷燬順序不正確。見例如http://msdn.microsoft.com/en-us/library/8183zf3x%28v=vs.100%29.aspx – hmuelner 2012-04-24 10:11:05

+0

@hmuelner修復。 – Oktalist 2014-07-26 20:49:47

2

對象將只毀壞了,當它有一個父指針,所以你可以使用:

MyWindow::MyWindow() 
: mybutton("Do Something", 0) 
{ 
    ... 
} 
+4

如果'QWidget'沒有父親,是不是會變成頂級窗口? – 2011-06-03 08:10:23

+0

是的,這是真的。如果您希望QWidget成爲另一個QWidget的子項,則必須給父項,這意味着您必須在堆上創建它。但是還有其他的QObject派生類,它們將它們用作成員變量是有意義的。 – hmuelner 2011-06-03 11:33:27

+0

-1:您的評論比實際答案更多。正如其他人所指出的那樣,根本沒有暗示'QObject'必須放在堆上,因爲它有一個父對象。 – Troubadour 2012-04-23 18:59:01

0

您應該堆上創建它,因爲QObject的必摧之:

class MyWindow : public QMainWindow 
{ 
    ... 
private: 
    QPushButton *myButton; 
} 

MyWindow::MyWindow() 
: mybutton(new QPushButton("Do Something", this)) 
{ 
    ... 
} 
+0

-1:正如其他人指出的,沒有必要在堆上創建它。 – Troubadour 2012-04-23 18:59:43

0

通話delete運營商不會崩潰你的應用程序,你可以閱讀以下報價

Qt的親子機制是在QObject中實現。當我們用一個父對象創建一個對象(一個控件,驗證器或任何其他類型)時,父對象將其添加到其子對象列表中。當父母被刪除時,它遍歷其子列表並刪除每個孩子。然後孩子們自己刪除他們所有的孩子,等等遞歸直到沒有人留下。父子機制大大簡化了內存管理,降低了內存泄漏的風險。我們必須調用delete的唯一對象是我們用new創建的對象,並且沒有父對象。如果我們刪除父對象之前的子對象,Qt會自動從父對象的子對象列表中刪除對象。

注意,父參數是NULL在默認情況下(默認參數) 這是QPushButton構造

QPushButton (const QString & text, QWidget * parent = 0) 

所以u可以使用

MyWindow::MyWindow() : mybutton(new QPushButton("Do Something")){ ... } 

和u可以在任何組件上調用delete並且任何時候都可以使用

Qt會照顧這個po int

4

該文檔說,從QObject派生的任何對象都會在其父對象被銷燬時自動銷燬; 這意味着調用刪除

號這意味着到特定實體的析構函數通話。

在你的例子中說,如果MyWindow被銷燬,這意味着已經調用了MyWindow的析構函數。而這又將調用已在QPushButton中實施的析構函數myButton

如果您有複合實體,只需要在該實體上調用析構函數,但不是delete,因此它不會崩潰。

在Qt中的父子關係並不需要特定的堆棧或堆。它可以是任何東西。

堆棧上的父子關係中的類似示例超過here

HTH ..

+2

父母如何知道孩子是否被堆分配?據我瞭解,調用析構函數不會釋放對象佔用的堆空間(「delete」是必需的) - 或者我錯了嗎? – 2011-06-03 08:43:53

+0

@ Jen,是的。如果它被分配給'新',你必須'刪除'它。我認爲它是由Qt元對象系統,該應用程序能夠識別孩子的分配..無法找到任何有關的文檔。將更新,如果我找到了什麼.. – liaK 2011-06-03 08:54:15

+0

@仁,但是不會崩潰。你試過了嗎?它力量崩潰吧? – liaK 2011-06-03 08:57:31

4

Object trees & ownership回答你的問題。基本上,當在堆上創建子對象時,它的父對象將被刪除。

另一方面,當在堆棧上創建子對象時,銷燬順序很重要。這個孩子將在之前銷燬其父,並將從其父母的列表中刪除,以便其析構函數不會被調用兩次。

該鏈接中還有一個示例,顯示有問題的銷燬順序。

+0

所以,如果我們有(堆棧或堆)複合,並且它被破壞(通過'delete'或者當堆棧對象的生命期結束時),首先調用複合的析構函數(並且執行它想做的任何事情,因爲這個邏輯是在QObject中實現的),那麼組合的子/成員就會被破壞(使用它的析構函數調用)並從對象中繼續保留它們(再次使用QObject的功能),然後QObject的析構函數終於被調用,並且看不到任何孩子 - 因此不需要雙重刪除。 – mlvljr 2012-05-26 14:44:05

0

讓我只需quote the source在這裏。

816 QObject::~QObject() 
817 { 
818  Q_D(QObject); 
819  d->wasDeleted = true; 
820  d->blockSig = 0; // unblock signals so we always emit destroyed() 
821 
    ... 
924 
925  if (!d->children.isEmpty()) 
926   d->deleteChildren(); 
927 
928  qt_removeObject(this); 
929 
930  if (d->parent)  // remove it from parent object 
931   d->setParent_helper(0); 
932 
933 #ifdef QT_JAMBI_BUILD 
934  if (d->inEventHandler) { 
935   qWarning("QObject: Do not delete object, '%s', during its event handler!", 
936     objectName().isNull() ? "unnamed" : qPrintable(objectName())); 
937  } 
938 #endif 
939 } 

    ... 

1897 void QObjectPrivate::deleteChildren() 
1898 { 
1899  const bool reallyWasDeleted = wasDeleted; 
1900  wasDeleted = true; 
1901  // delete children objects 
1902  // don't use qDeleteAll as the destructor of the child might 
1903  // delete siblings 
1904  for (int i = 0; i < children.count(); ++i) { 
1905   currentChildBeingDeleted = children.at(i); 
1906   children[i] = 0; 
1907   delete currentChildBeingDeleted; 
1908  } 
1909  children.clear(); 
1910  currentChildBeingDeleted = 0; 
1911  wasDeleted = reallyWasDeleted; 
1912 } 

因此,大家可以看到,QObject確實delete它的每一個在析構函數的孩子。另外,析構函數被執行的任何成員的析構函數都是before;所以如果問題組合等於父母 - 那麼成員QObject將沒有任何機會從其父母的子女列表中刪除自己。

很不幸,這意味着你不能撰寫其父QObject。但是,您可以編寫其他對象,以及在堆棧上進行分配 - 只要您保證破壞對象或將其父對象重置爲之前父對象開始破壞。

相關問題