分析了這兩種用法,真想吐槽兩句,這兩個特性確實有實際需要,但客觀來說,現有標准足夠用,而且帶來的代價也非常大,又給C++復雜的語法糖重重的抹了一筆!!!
一、繼承構造函數
繼承構造函數的引入原因:如果基類的構造函數很多,那麼子類的構造函數想要實現同樣多的構造接口,必須一一調用基類的構造函數,有點麻煩
於是乎:C++11引入繼承構造函數
class _A
{
public:
_A( int _InInt ) {;}
_A( double _InDouble, int _InInt ) {;}
_A( float _InFloat, int _InInt, const char* _Char ) {;}
};
class _B : public _A
{
public:
using _A::_A; // 使用_A中的構造函數
// Somthing...
virtual void _ExtraInterface() {;}
}; 一句using _A::_A; 把基類中的構造函數都繼承到派生類_B中, 這樣最開始的那段代碼就可以擺脫基類那麼多構造函數接口了。
但是:
(1) C++11中的繼承構造函數特性最有用的場合就是,派生類只是在基類的基礎上添加了幾個新的接口, 這個時候繼承構造函數最能夠展現威力.
但是缺陷就是, 繼承構造函數只會初始化基類中的成員變量(畢竟只是從基類繼承下來的), 對於派生類中的變量無能為力,
(2)不過,可以配合另一個C++11中的新特性: 數據成員就地初始化,來解決這個問題。但是,這種做法導致子類的成員不能在構造函數的參數列表中體現出來。
(3)一旦,子類繼承了基類的構造函數,那麼子類就不會自動生成默認構造函數。
struct _Base
{ _Base( int ) {} };
struct _Derived : _Base
{ using _Base::_Base; };
int main( int _Argc, char* *_Argv )
{
_Derived __derived; // 編譯失敗, 因為沒有提供_Derived 的默認構造函數
return 0;
}
二、委派構造函數
托構造函數允許類中的一個構造函數通過初始化列表方式來調用同一個類中的另一個構造函數。
class Info {
public:
Info() : Info(1, 'a') { }
Info(int i) : Info(i, 'a') { }
Info(char e): Info(1, e) { }
private:
Info(int i, char e): type(i), name(e) { /* 其他初始化 */ }
int type;
char name;
// ...
};是減少冗余代碼和重復代碼的好辦法,能提高代碼的可讀性。
但是,不要形成委托環
struct Rule2 {
int i, c;
Rule2(): Rule2(2) {}
Rule2(int i): Rule2('c') {}
Rule2(char c): Rule2(2) {}
};
Rule2定義中,Rule2()、Rule2(int)和Rule2(char)都依賴於別的構造函數,形成環委托構造關系。這樣的代碼通常會導致編譯錯誤