C++繼承中子類的構造方法

構造方法是用來初始化類的對象,與父類的其他成員不同,在C++11之前,不能被子類繼承(子類可以繼承父類所有的成員變量和成員方法,但不繼承父類的構造方法),因此,爲了完成基類的初始化,需要在初始化列表中調用基類的構造函數,從而完成構造函數的傳遞,如果基類有多個構造函數,子類需要實現與基類相對應的(多個)構造函數。

如果沒有顯示的構造函數,編譯器會給一個默認的構造函數,並且該默認的構造函數僅僅在沒有顯示的申明構造函數的情況下創建。
如下:

class Base
{
public:
    Base(char c) : m_nIndex(0), m_cChar(c){}
    Base(int a) : m_nIndex(a), m_cChar('0'){}
	void display()
    {
    	cout << m_nIndex << "    " << m_cChar << "    Base test..." << endl;	
	}
private:
    int m_nIndex;
    char m_cChar;
};

class SubClass : public Base
{
public:
    SubClass(char c) : Base(c){}
    SubClass(int a) : Base(a){}

    void display()
    {
        // to do something...
        Base::display();
        cout << "    test...    " << endl;
    }
};

由上面的例子可以看出,子類 SubClass 的實現中,由於繼承了基類 Base,所以在類 SubClass 的構造函數的初始化列表中,調用了基類 Base 的構造函數,並且基類 Base 有幾個構造函數,子類 SubClass 則相應的實現幾個對應的構造函數,這樣,假設基類 Base有很多個構造函數,則需要全部實現對應的構造方法,這種方法無疑增加了麻煩,降低效率。

而C++11中,出現了繼承構造函數(Inheriting Constructor),使用關鍵字 using 來申明基類的構造函數。
如下:

class Base
{
public:
    Base(char c) : m_nIndex(0), m_cChar(c){}
    Base(int a) : m_nIndex(a), m_cChar('0'){}
	void display()
    {
    	cout << m_nIndex << "    " << m_cChar << "    Base test..." << endl;	
	}
private:
    int m_nIndex;
    char m_cChar;
};

class SubClass : public Base
{
public:
    using Base::Base;
    void display()
    {
        // to do something...
        Base::display();
        cout << m_nValue << "    " << m_bTure << "    test..." << endl;	
    }

private:

#if 0
    int m_nValue{ 0 };    //C++11 之後可以使用的對類中的成員進行初始化的方法
    bool m_bTure{ true };     //默認初始化爲false
#else
    int m_nValue;
    bool m_bTure; 
#endif
};

上面的例子,我們使用 using 關鍵字將基類 Base 的構造函數繼承給了子類 SubClass,這樣減少了編寫子類構造函數來完成基類 Base 的初始化。

C++11 標準規定,繼承構造函數與類的一些默認函數(默認構造、析構、拷貝構造函數等)一樣,是隱式聲明,如果一個繼承構造函數不被相關代碼使用,編譯器不會爲其產生真正的函數代碼。

需要注意的是:

  • 繼承構造函數無法初始化子類的成員變量,比如上面例子中的 else 分支,非靜態成員變量 m_nValue 和 m_bTure 未被進行初始化,而 if 分支,是C++11特性中支持的初始化成員變量的方法。

    兩次測試結果如下:
    else分支:

    if分支:
    在這裏插入圖片描述
    同樣的,還可以通過新增子類構造函數的方法使用初始化列表進行初始化。
    比如:

class SubClass : public Base
{
public:
    using Base::Base;
    SubClass(int a, bool b) : Base(a), m_nValue(a), m_bTure(false){}
    void display()
    {
        // to do something...
    }

privateint m_nValue;
    bool m_bTure; 
};
  • 基類構造函數有默認值時, 會產生多個默認構造函數,繼承構造函數是不會繼承基類構造函數中的默認值。
    如下:
class Base
{
public:
	Base(int a = 4, char c = 'a') : m_nIndex(a), m_cValue(c){}
	void display()
	{
		cout << m_nIndex << "    " << m_cValue << "    Base test..." << endl;		
	}
	
private:
	int m_nIndex;
	char m_cValue;
};

class SubClass : public Base
{
public:
	using Base::Base;
	void display()
	{
		Base::display();
		cout << m_nValue << "    " << m_bTure << "    test..." << endl;		
	}
	
private:
#if 0
    int m_nValue{0};    //C++11 之後可以使用的對類中的成員進行初始化的方法
    bool m_bTure{true};     //默認初始化爲false,可以置頂初始值 bool m_bTure{true}; 
#else
    int m_nValue;
    bool m_bTure; 
#endif
};

產生的默認構造函數:

Base()
Base(int a)
Base(char c)
Base(int a, char c)
Base(const Base& other)

相應的子類也會產生對應的構造函數。
運行上述代碼的結果:
在這裏插入圖片描述
由上圖可以看出,基類Base的成員變量全部由默認參數初始化,但是子類SubClass的成員變量沒有繼承基類的默認參數。出現了隨機值。
因此,在基類的構造函數中有默認值時,要注意子類的成員變量進行初始化。

  • 多繼承的情況下,使用繼承構造函數可能會出現編譯錯誤。
class Base1
{
public:
    Base1(int a) : m_nIndex(a){}
private:
    int m_nIndex;
};

class Base2
{
public:
    Base2(int a) : m_nIndex(a){}
private:
    int m_nIndex;
};

class SubClass : public Base1, public Base2
{
public:
    using Base1::Base1;
	using Base2::Base2;
	
#if 0	//可避免編譯錯誤的情況
	SubClass(int a) : Base1(a), Base2(a){}
#endif
    void display()
    {
        // to do something...
        cout << m_nValue << "    " << m_bTure << "    test..." << endl;	
    }
private:
#if 0
    int m_nValue{ 0 };    //C++11 之後可以使用的對類中的成員進行初始化的方法
    bool m_bTure{ true };     //默認初始化爲false
#else
    int m_nValue;
    bool m_bTure; 
#endif
};

編譯上述代碼,出現:
在這裏插入圖片描述
出現的原因是:多個繼承的時候,存在出現繼承的構造可能在派生類中出現一樣的情況(函數簽名),避免出現這種錯誤的方法,使用顯示定義構造函數的方法。

  • 基類的構造函數被申明爲私有,或者基類是重需基類,則不能進行申明繼承構造函數。

以上代碼使用測試用例:

int main(int argc, char *argv[])
{
	SubClass* d = new SubClass(2);
	d->display();
	
	delete d;
	d = NULL;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章