原文: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對象樹的概念,關於對象樹,小豆君會在后面的分享中為大家介紹。