C++呼叫父類的建構函式規則
構造方法用來初始化類的物件,與父類的其它成員不同,它不能被子類繼承(子類可以繼承父類所有的成員變數和成員方法,但不繼承父類的構造方法)。因此,在建立子類物件時,為了初始化從父類繼承來的資料成員,系統需要呼叫其父類的構造方法。
如果沒有顯式的建構函式,編譯器會給一個預設的建構函式,並且該預設的建構函式僅僅在沒有顯式地宣告建構函式情況下建立。
構造原則如下:
1. 如果子類沒有定義構造方法,則呼叫父類的無引數的構造方法。
2. 如果子類定義了構造方法,不論是無引數還是帶引數,在建立子類的物件的時候,首先執行父類無引數的構造方法,然後執行自己的構造方法。
3. 在建立子類物件時候,如果子類的建構函式沒有顯示呼叫父類的建構函式,則會呼叫父類的預設無參建構函式。
4. 在建立子類物件時候,如果子類的建構函式沒有顯示呼叫父類的建構函式且父類自己提供了無參建構函式,則會呼叫父類自己的無參建構函式。
5. 在建立子類物件時候,如果子類的建構函式沒有顯示呼叫父類的建構函式且父類只定義了自己的有參建構函式,則會出錯(如果父類只有有引數的構造方法,則子類必須顯示呼叫此帶參構造方法)。
6. 如果子類呼叫父類帶引數的構造方法,需要用初始化列表的方式。
結論:子類建構函式必須要呼叫父類的建構函式(無論顯式還是隱式),本質原因在於繼承的性質決定了必須先有父再有子!
看一個例子:在執行new A1時,下面程式碼的輸出是什麼
#include <iostream>
using namespace std;
int init(const std::string & info)
{
std::cout << info << std::endl;
return 0;
}
class A
{
int m_x;
public:
A():m_x(init("Init A::m_x"))
{
init("Call A::A()");
}
};
class A1:public A
{
int m_x;
int m_y;
public:
A1(): m_y(init("Init A1::m_y")), m_x(init("Init A1::m_x"))
{
init("Call A1::A1()");
}
};
打印出來的結果為:
Init A::m_x
Call A::A() ==>是因為隱式呼叫了父類的建構函式
Init A1::m_x ==>按照成員變數的宣告順序“而非”初始化列表指定的順序來進行構造
Init A1::m_y
Call A1::A1()