1.編譯器生成的成員函式
(1)預設建構函式(沒有引數,或所有引數都有預設值)——確保物件總能被正確地初始化
star rigel;
star pleiades[6];
功能:1)呼叫基類的預設建構函式以及呼叫本身是物件的成員所屬類的預設建構函式;
2)如果派生類建構函式的成員初始化列表中沒有顯式呼叫基類建構函式,則編譯器將使用基類的預設建構函式來構造派 生類物件的基類部分
3)如果類包含指標成員,則必須初始化這些成員,提供乙個顯式預設建構函式,將所有的類資料成員都初始化為合理的值
(2)複製建構函式(接受其所屬類的物件作為引數)
新物件的每個成員都被初始化為原始物件相應成員的值,如果成員為類物件,則初始化該成員時,將使用相應類的複製建構函式。
//star類的複製建構函式原型
star(const star &);
下述情況下,將使用複製建構函式:
1)將新物件初始化為乙個同類物件;
2)按值將物件傳遞給函式;
3)函式按值返回物件;
4)編譯器生成臨時物件
(3)賦值運算子
預設的賦值運算子用於處理同類物件之間的賦值:
star sirius;
star alpha=sirius; //初始化
star dogstar;
dogstar=sirius; //賦值
另外,如果需要顯式定義複製建構函式,則需要顯式定義賦值運算子:
star & star::operator=(const star &);
如果希望能夠將字串賦給star物件,則顯式定義下面的運算子:
star & star::operator=(const char*)
2.其他的類方法
(1)建構函式
建構函式建立新的物件,建構函式不能被繼承(因為繼承意味著派生類物件可以使用基類的方法,而建構函式在完成其工作之前,物件並不存在)
(2)析構函式
一定要定義顯式析構函式來釋放類建構函式使用new分配的所有記憶體,並完成類物件所需的任何特殊的清理工作。對於基類,即使它不需要析構函式,也應提供乙個虛析構函式
(3)轉換
轉換建構函式:在帶乙個引數的建構函式原型中使用explicit將禁止進行隱式轉換,但仍允許顯示轉換
class star
;...
star north;
north="polaris"; //not allowed
north=star("polaris"); //allowed
轉換函式:將類物件轉換為其他型別,轉換函式可以是沒有引數的類成員函式,也可以是返回型別被宣告為目標型別的類成員函式。即使沒有宣告返回型別,函式也應返回所需的轉換值
star::star double() //converts star to double
star::star const char *() //converts to const char
(4)按值傳遞物件與傳遞引用
按值傳遞物件涉及到生成臨時拷貝,即呼叫複製建構函式,然後呼叫析構函式。呼叫這些函式需要時間,複製大型物件比傳遞引用花費的時間多,故傳遞引用可以提高效率
(5)返回物件和返回引用
返回物件:
vector vector::operator+(const vector & b)const
返回引用:
const stock & stock::topval(const stock & s)const
直接返回物件與按值傳遞物件相似:它們都生成臨時副本
返回引用與按引用傳遞物件相似:呼叫和被呼叫函式對同乙個物件進行操作
(6)使用const
確保方法不修改引數:
star::star(const char * s) //won't change the string to which s points
確保方法不修改呼叫它的物件:
void star::show() const //won't change invoking object
3.公有繼承的考慮因素
(1)is-a關係
表示is-a關係的方式之一是,無需進行顯式型別轉換,基類指標就可以指向派生類物件,基類引用可以引用派生類物件。另外,反過來是行不通的,即不能在不進行顯式型別轉換的情況下,將派生類指標或引用指向基類物件,這種顯式型別轉換(向下強制轉換)可能有意義,也可能沒有,這取決於類宣告
(2)什麼不能被繼承
建構函式是不能繼承的:建立派生類物件時,必須呼叫派生類的建構函式,派生類建構函式通常使用成員初始化列表語法來呼叫基類建構函式,以建立派生物件的基類部分。如果派生類建構函式沒有使用成員初始化列表語法顯式呼叫基類建構函式,將使用基類的預設建構函式。在繼承鏈中,每個類都可以使用成員初始化列表將資訊傳遞給相鄰的基類。
析構函式是不能繼承的:在釋放物件時,程式將首先呼叫派生類的析構函式,然後呼叫基類的析構函式。如果 基類有預設析構函式,編輯器將為派生類生成預設析構函式。通常,對於基類,其析構函式應設定為虛的
賦值運算子是不能繼承的:派生類繼承的方法的特徵標與基類完全相同,但賦值運算子的特徵標隨類而異,這是因為它包含乙個型別為其所屬類的形參
(3)賦值運算子
是否可以將基類物件賦給派生物件?
如果派生類包含了這樣的建構函式,即對將基類物件轉換為派生類物件進行了定義,則可以將基類物件賦給派生物件。如果派生類定義了用於將基類物件賦給派生物件的賦值運算子,則也可以這樣做。如果上述兩個條件都不滿足,則不能這樣做,除非使用顯式強制型別轉換
(4)私有成員與保護成員
對派生類而言,保護成員類似於公有成員;對外部而言,保護成員與私有成員類似;派生類可以直接訪問基類的保護成員,但只能通過基類的成員函式來訪問私有成員
(5)虛方法
設計基類時,必須確定是否將類方法宣告為虛的,如果希望派生類能夠重新定義方法,則應在基類中將方法定義為虛的,這樣可以啟用晚期聯編(動態聯編)
(6)析構函式
基類的析構函式應當是虛的。當通過指向物件的基類指標或引用來刪除派生物件時,程式將首先呼叫派生類的析構函式,然後呼叫基類的析構函式,而不僅僅是呼叫基類的析構函式
(7)友元函式
友元函式並非類成員,不能繼承,通過強制型別轉換,派生類引用或指標轉換為基類引用或指標,然後使用轉換後的指標或引用來呼叫基類的友元函式:
ostream & operator<<(ostream & os, const hasdma & hs)
{ //type cast to match operator<<(ostream & ,const basedma &)
os<<(const basedma &)hs;
os<<"style: "<(8)有關使用基類方法的說明
以公有方式派生的類的物件可以通過多種方式來使用基類的方法。
1)派生類物件自動使用繼承而來的基類方法,如果派生類沒有重新定義該方法
2)派生類的建構函式自動呼叫基類的建構函式
3)派生類的建構函式自動呼叫基類的預設建構函式,如果沒有在成員初始化列表中指定其他建構函式
4)派生類建構函式顯式地呼叫成員初始化列表中指定的基類建構函式
5)派生類方法可以使用作用域解析運算子來呼叫公有的和受保護的基類方法
6)派生類的友元函式可以通過強制型別轉換,將派生類引用或指標轉換為基類引用或指標,使用該引用或指標來呼叫基類的友元函式
(一四三)類設計回顧
編譯器自動生成的特殊成員函式 預設建構函式 當建構函式無引數 或所有引數都有預設值時 二者不能同時存在 則是預設建構函式。自動生成的預設建構函式,將呼叫基類的預設建構函式 如果類的資料成員是另乙個類的物件,那麼這個資料成員在生成的時候,也會呼叫其預設建構函式。假如定義了某個建構函式,那麼編譯器將不會...
C 類繼承7 類設計回顧
編譯器會自動生成一些公有的成員函式 特殊成員函式。1 預設建構函式 提供建構函式的動機之一是確保物件總能被正確地初始化。如果類包含指標成員,則必須初始化這些成員。最好提供乙個顯式預設建構函式,將所有的類資料成員都初始化為合理的值。如果定義了某種建構函式,編譯器將不會定義預設建構函式。如果沒有定義任何...
設計原則回顧
回顧根據乙個講師學習做些總結 設計原則 1.我們程式設計針對介面程式設計而不是針對實現程式設計 客戶端這樣只關心介面,而不關心物件的特定型別 2.優先使用物件組合,而不是類的繼承 繼承在某種程度上破壞了封裝性 3.封裝變化點 體現了類的聚合,把變化的地方封裝以不至於牽一髮而動全身 實現了松耦合 4....