一、由編譯器生成的成員函數
1)默認的構造函數
默認構造函數定義為沒有參數,或者有默認的參數值。當用戶自己未定義時,系統可以提供。
自動生成的默認構造函數,會調用繼承的基類的默認構造函數來構造派生類的基類部分。
若Star是一個類,則
Star orig;
Star array[6];都將需要默認構造函數。
如果自己定義了構造函數,則系統不會再生成默認構造函數,這個時候最好自己要定義一個默認構造函數。
構造函數 -- 【確保對象的生成】 -- 最好提供顯式的默認構造函數,以確保對象能夠正確的初始化為合理值。
2)復制構造函數
Star類的復制構造函數圓形如下:
Star(const Star &)
通常,我們會在一下情況下用到復制構造函數:
* 將新對象初始化為一個同類對象
* 函數按值傳遞對象參數
* 函數返回對象(而不是對象的引用)
* 生成臨時對象
如果自己沒有顯式的定義復制構造函數,編譯器將會自動生成一個其原型(但不提供函數定義??),以使得新對象的的每個成員初始化為原始對象相應的成員。
但是,當出現需要深度復制的情況時(使用new構造成員),或者需要修改的靜態變量,這個時候一定要自己定義復制構造函數!!
例如:
string(const string & s)
{
// new char []
}
3)賦值運算符
在同類對象之間進行賦值操作,但不要把賦值和復制初始化混淆!!
【如果語句創建新對象,一般是復制初始化構造;語句修改已有對象,則是賦值】
Star orig;
Star pre = orig; // copy ctor
Star post;
post = pre; // copy assignment
賦值運算符返回對象的引用(使得可以連續賦值)。
orig = pre = post;
這是string類的賦值運算符重載:(見《C++ string類字符串的常用操作及實現》,同時實現“自我賦值”和"異常安全處理")
string & string::operator=(const string &) const ;
二、類設計的其它注意事項
1)構造函數不能夠被繼承(使用),只有自己需要生成對象時被使用。繼承的派生類構造函數,會調用基類的構造函數。
2)析構函數,在使用new動態生成成員變量是一定要顯式定義析構函數;當基類中存在virtual或者pure virtual時,將析構函數也定義為virtual。
3)轉換構造函數,如果你不希望出現隱式的類型轉換,使用【explicit】聲明函數,但仍然可以使用顯式的強制轉換。
例如:
explict string(const char *);
4)按值傳遞和按引用傳遞
我們知道,一般情況下在類設計中都是用按引用傳遞,按值傳遞會隱式的調用復制構造函數和析構函數,在返回大型類時極其影響效率。可以節省時間和內存!!
按引用傳遞的另外原因:在繼承使用虛函數時,被定義接受基類引用的參數可以接受派生類的引用。
5)const的使用
盡可能的使用const,但要注意場合。確保const參數在傳遞過程中不會修改其屬性(常量),【可以將非const傳給const參數,但禁止將const傳給非const】。
三、共有繼承的注意事項
1)IS-A關系式典型的基類 - 派生(is a king of),HAS-A有種接口的趕腳,接口的實現(is implemented as a),用友元函數實現(uses a)。純自己的感覺,有誤請指正。
2)基類的構造函數、析構函數和(一般情況下)賦值函數都不能繼承。可以將派生類賦值給基類,反過來則maybe。
3)對於公共用戶,使用保護成員和私有成員一樣;對於派生類而言,使用保護乘員和公有成員一樣。
派生類可以直接訪問保護乘員,但只能通過基類的共有方法訪問私有成員,相對來講私有成員具有更好的安全性。
保護成員則可以簡化編碼,提高訪問速度,但是這會使得派生類直接訪問和修改基類的保護成員。
【使用私有成員比保護成員更好(盡可能的使用),但是保護方法很有用】
4)虛方法
設計基類時將方法定義為虛,使得【多態】派生類能夠重新定義方法,這樣可以使用【動態聯編】。
純虛函數使得類ABC【只定義接口,不涉及實現】,不能生成真正的對象。
5)友元函數
友元函數不是類的方法,因此不能夠繼承,在派生類中需要重新定義。
如果要使用基類的friend 函數,一般我們會使用【強制轉換】,將派生類的指針或者引用轉換成基類的指針或引用。
-- 【C++ Primer Plus】溫習小結。