2013-09-24 38 views
5

當創建用C GUI ++和Qt你可以這樣創建例如標籤:C++ - 爲什麼我要在堆上創建這些小部件?

QLabel* label = new QLabel("Hey you!", centralWidgetParent); 

這在堆上創建對象,將呆在那裏,直到我手動刪除或父被摧毀。我現在的問題是爲什麼我需要一個指針?爲什麼不在堆棧上創建它?

//Create a member variable of Class MainWindow 
QLabel label; 

//Set parent to show it and give a text so the user can see it 
    QWidget* centralWidget = new QWidget(this); //Needed to add widgets to the window 
    this->setCentralWidget(centralWidget); 
    label.setParent(centralWidget); 
    label.setText("Haha"); 

這工作正常,我可以看到標籤,它並沒有消失。

我們在C++中使用指針讓事物壽命更長,因此我們可以在各種範圍內使用對象。但是,當我創建一個成員變量,它不會留下,直到對象被破壞?

編輯: 也許我沒有說清楚。這是MainWindow類:

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 
    QLabel label; //First introduced here... 

public: 
    MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 
}; 

//Constructor 
MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
{ 
    QWidget* centralWidget = new QWidget(this); 
    this->setCentralWidget(centralWidget); 
    label.setParent(centralWidget); 
    label.setText("Haha"); 
} 

回答

3

因爲這就是Qt的設計方式。我意識到這不是一個令人滿意的答案,但Qt的設計原理是「小部件在堆上創建,父母負責刪除他們的孩子」。

認識到Qt的起源比我們認爲的「現代C++」陳舊。

+0

嗯......這至少讓人感覺。謝謝。 – Davlog

8

如果您的label超出範圍,將會調用析構函數(QLabel::~QLabel)。從docs

銷燬該對象,刪除其所有子對象。

沒有必要在堆上創建對象 - 你可以把對象放在堆棧上,但是你需要對對象的生命週期負責(關於分配數據的最有問題的問題之一堆是「誰和什麼時候應該刪除這些對象?」的問題,而在Qt中它是由層次結構處理的 - 每當你刪除你的小部件時,所有的子部件都將被刪除)。

爲什麼你的程序工作 - 我不知道 - 它可能不工作(label在範圍的末尾被銷燬)。另一個問題是 - 如果您沒有參考它,您將如何更改label的文本(例如,來自某個插槽)?

編輯我剛纔看到你的labelMainWindow的成員。擁有一個完整的對象並不是指向作爲類的成員的對象的指針,因爲它在MainWindow之前不會被銷燬。請注意,如果您創建MainWindow的情況是這樣的:

MainWindow *w = new MainWindow(); 

label將在堆上創建。

+0

我可以在任何地方打電話給標籤(某些功能)。它是我的MainWindow類的成員,所以我可以在任何插槽,公共或私人函數中使用它。 – Davlog

3

將小部件分配爲局部變量通常不是一個好主意,因爲通常它會在以任何方式使用之前超出範圍;因爲QObject通過其「父 - 子」關係(與C++析構函數很好地集成)支持組合模式,通常最簡單的事情就是利用這樣的特性。

在另一方面,你可以使你MainWindow類的成員,或者在一般的分配以任何方式,使得它具有壽命比其父的壽命少。事實上,當這樣的QLabel被銷燬時,它會自動從其父母註銷,避免雙重釋放。但通常只是在堆上分配小部件,將它們註冊爲當前窗口的子項更爲舒適,因爲通常在創建小部件後(例如標籤),實際上並不需要訪問許多小部件,所以不需要雜亂無章你的班級有無用的數據成員。你只需將new QLabel(this, ...)放入你的窗口構造函數中即可。

你應該做什麼,相反,是不new如果他們的壽命越來越長比他們父母的生命週期(例如,把它們放在一個全局或靜態變量)分配你的部件 - 這樣做會導致父試圖以delete的方式對其進行破壞,最多隻會導致崩潰,最糟糕的是無聲的內存損壞。這可以被固定(通過手動註銷你的類的析構函數中的小部件),但我無法想象任何情況下,這樣的事情會有用。

1

主要原因 - 動態創建/刪除小部件的可能性。 QObject(和QWidget)設計爲不能有拷貝構造函數的類,所以你不能通過參數(通過值/引用)。所以在所有情況下使用指針都會使代碼更加簡單明瞭。

4

另一件事要記住的是,Qt使用,其中對象數據是隱式共享和你實際實例化類背後所管理的所謂平普爾的範例。看到這裏:http://qt-project.org/wiki/Dpointer

底線是,如果你是在堆棧上分配,以避免使用堆,Qt只是拉你一個快速的一堆,並使用堆。

相關問題