QT 的 parent 該如何理解


對話框是GUI程序和用戶進行簡短交互的頂層窗口,所謂頂層窗口即始終在主窗口之上顯示。QDialog是Qt所有類型的對話框窗口的基類,它繼承於QWidget,是一種容器類型組件。

QWidget是所有窗口類的抽象,它也可以生成對話框,但是對話框是常見的窗口組件,若每次要使用對話框,都利用QWidget來生成並設置相關參數,顯然十分繁瑣。所以Qt為我們封裝了另外一個子類QDialog,專門用於生成對話框

       QDialog類是對話框窗口的基類。對話框窗口是主要用於短時期任務以及用戶進行簡要通訊的頂級窗口。QDialog可以是模態對話框也可以是非模態對話框。QDialog支持擴展性並且可以提供返回值。他們可以有默認按鈕。QDialog也可以有一個QSizeGrip在它的右下方,使用setSizeGripEnable()。

注意:QDialog使用父窗口部件的方法和Qt中其他類不同。對話框總是頂級窗口部件,但是如果它有一個父對象,它的默認位置就是父對象的中間。他也將和父對象共享工具條條目。

QDialog 是最普通的頂級窗口(一個不會被嵌入到父窗口部件的窗口部件叫頂級窗口部件)。通常情況下,頂級窗口部件是有框架和標題欄的窗口(盡管使用了一定的窗口部件標記,創建頂級窗口部件時也可以沒有這個修飾)在Qt中。QMainWindow和不同的QDialog的子類是最普通的頂級窗口。

非頂級窗口部件就是子窗口部件。他們是他們的父窗口部件中的子窗口。你通常不能在視覺角度從它們的父窗口部件辨別一個子窗口部件。在Qt中的絕大多數其他窗口部件僅僅作為子窗口部件才是有用的。(當然把一個按鈕作為或者叫做頂級窗口部件也是有可能的,但是絕大多數人喜歡把它們的按鈕放到其他部件當中)

   如果是頂級對話框,那就是基於QDialog創建,如果是主窗體,就基於QMainWindow,如果不確定,或有可能作為頂級窗體,或有可能嵌入到其他窗體中,則基於QWidget創建。

該如何理解下面段代碼的第二行QWidget(parent)

Widget::Widget(QWidget *parent) :
    QWidget(parent)
{
 
}

在講解原因之前,先請大家看下面的一個例子

#include <iostream>
 
using namespace std;
 
class Base
 
{
 
    public:
 
    Base() :m_num(0){
 
        cout << "this is Base()" << endl;
 
    }
 
    Base(int val):m_num(val){
 
        cout << "this is Base(int val)" << endl;
 
    }
 
    private:
 
    int m_num;
 
};    

1。 上方代碼定義了一個基類Base,並且有兩個構造函數,一個是默認構造函數,一個是有一個整型參數的構造函數。

class BaseChild: public Base
 
{
 
    public:
 
    BaseChild(){
 
        cout << "this is BaseChild()" << endl;
 
    }
 
    BaseChild(int val): Base(val){
 
        cout << "this is BaseChild(val)" << endl;
 
    }
 
    private:
 
    int m_num;
 
};

2。 上方代碼定義了一個BaseChild類,並繼承Base類,同樣的,它也定義了兩個構造函數,一個默認,一個有整型參數。

int main(int argc, char *argv[])
 
{
 
    BaseChild child1;
 
    BaseChild child2(5);
 
 
    return 0;
 
}

3。 main函數實例化了兩個子類實例,child1,child2。child1調用默認構造函數。child2調用有整型參數的構造函數。

現在,我們運行程序,會有如下打印:

     this is Base()!

     this is Base(int Val)!

     this is BaseChild()!

     this is BaseChild(int Val)!

看到了嗎,我們發現:

  • 創建child1時,是先調用了Base的默認構造函數,再調用自己的默認構造函數
  • 創建child2時,是先調用了Base(int)這個構造函數,再調用自己的整型參數構造函數。

所以我們回頭看BaseChild的構造函數

BaseChild(int val): Base(val){
 
    cout << "this is BaseChild(val)" << endl;
 
}

細心的同學,可能早就發現了,初始化列表中的Base(val)正是調用了我們Base基類的有參構造函數,而這樣的寫法就剛好是我們開頭代碼中的那段

Widget::Widget(QWidget *parent) :QWidget(parent)

所以Widget是調用了QWidget下面的構造函數

QWidget(QWidget* parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());

所以得出如下總結:

總結: 
如果不指定構造函數,則派生類會調用基類的默認構造函數 ·
派生類構造函數的初始化列表只能初始化派生類成員,不能直接初始化繼承成員,如果想 要調用基類的有參構造函數,則可以在派生類的初始化列表中顯示指定

以上總結,也告訴我們,當定義一個類時,最好為該類定義默認構造函數。

至此,我們明白了這個寫法為什么會這樣寫。

好的,那么我們又提出一個問題,“調用QWidget(parent)這個構造函數,QWidget父類都做了哪些動作呢?”

下面是QWidget源碼中的一部分節選:

QWidget::QWidget( QWidget *parent, const char *name, WFlags f )
  : QObject( parent, name ), QPaintDevice( PDT_WIDGET ),
  pal( parent ? parent->palette() // use parent's palette
   : *qApp->palette() ) // use application palette
{
  if ( parent ) 
  {     QChildEvent
*e = new QChildEvent( Event_ChildInserted, this );     QApplication::postEvent( parent, e );   } }

大家從上面可以看出,如果parent參數非空的話,那么該構造函數使用了其父窗口的調色板,並且發送了QChildEvent事件,這會讓新的窗口成為parent所指窗口的子窗口,那么當父窗口被刪除時,子窗口也會自動的被刪除。

初始化列表中的Base(Vale)正好調用了Base基類的有參構造函數。

    同理,可以理解Widget::Widget(QWidget *parent) :QWidget(parent)。Widget::Widget(QWidget *parent) :QWidget(parent)調用了QWidget基類的下述構造函數:

QWidget(QWidget*parent =Q_NULLPTR,Qt::WindowFlagsf =Qt::WindowFlags());

如果不指定構造函數,則派生類會調用基類的默認構造函數 。派生類構造函數的初始化列表只能初始化派生類成員,不能直接初始化繼承成員,如果想 要調用基類的有參構造函數,則可以在派生類的初始化列表中顯示指定。

    當定義一個類時,最好為該類定義一個默認構造函數。

對應語法:

        派生類::派生類構造函數(總參數列表):基類構造函數(參數列表)  //基類構造函數的參數列表是實參。
{
派生類中的數據成員初始化;

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM