正確理解Widget::Widget(QWidget *parent) :QWidget(parent)這句話


原文:https://zhuanlan.zhihu.com/p/31310536

/********原文********/

最近很多學習Qt的小伙伴在我的微信公眾號私信我,該如何理解下面段代碼的第二行QWidget(parent)

1 Widget::Widget(QWidget *parent) :
2     QWidget(parent)
3 {
4 
5 }

 

為了統一回復大家,小豆君特意寫了這篇文章,方便初學者們學習。

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

 1 #include <iostream>
 2 using namespace std;
 3 class Base
 4 {
 5 public:
 6     Base() :m_num(0){
 7         cout << "this is Base()" << endl;
 8     }
 9     Base(int val):m_num(val){
10         cout << "this is Base(int val)" << endl;
11     }
12 private:
13     int m_num;
14 };

 

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

 

 1 class BaseChild: public Base
 2 {
 3 public:
 4     BaseChild(){
 5         cout << "this is BaseChild()" << endl;
 6     }
 7     BaseChild(int val): Base(val){
 8         cout << "this is BaseChild(val)" << endl;
 9     }
10 private:
11     int m_num;
12 };

 

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

 

1 int main(int argc, char *argv[])
2 {
3     BaseChild child1;
4     BaseChild child2(5);
5 
6     return 0;
7 }

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

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

看到了嗎,我們發現:

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

 

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

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

 

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

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

 

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

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

 

所以得出如下總結:

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

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

 

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

 

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

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

 1 QWidget::QWidget( QWidget *parent, const char *name, WFlags f )
 2     : QObject( parent, name ), QPaintDevice( PDT_WIDGET ),
 3       pal( parent ? parent->palette()        // use parent's palette
 4            : *qApp->palette() )            // use application palette
 5 {
 6     if ( parent ) {
 7     QChildEvent *e = new QChildEvent( Event_ChildInserted, this );
 8     QApplication::postEvent( parent, e );
 9     }
10 }

 

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

這其實是用到了Qt對象樹的概念,關於對象樹,小豆君會在后面的分享中為大家介紹。

 


免責聲明!

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



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