(一四三)类设计回顾
編譯器自動生成的特殊成員函數:
默認構造函數:
當構造函數無參數、或所有參數都有默認值時(二者不能同時存在),則是默認構造函數。
?
自動生成的默認構造函數,將調用基類的默認構造函數;如果類的數據成員是另一個類的對象,那么這個數據成員在生成的時候,也會調用其默認構造函數。
?
假如定義了某個構造函數,那么編譯器將不會定義默認構造函數。
?
假如類數據成員有指針,應該在默認構造函數中正確為其分配內存地址。
?
?
復制構造函數:
原型:類名(const?類名&?);
使用復制構造函數的四種情況(關鍵是在聲明一個類并初始化時):
①將新對象初始化為一個同類對象(如Man?a=b;?Man是類名,下同);
②按值將對象傳遞給函數(如void?show(Man?a));
③函數按值返回對象(如Man?show(););
④編譯器生成臨時對象(臨時對象通常在以下情況產生:①類型轉換;②按值返回;③按值傳遞;④對象定義);
?
具體情況:
①類里沒有聲明復制構造函數,也沒用使用——編譯器提供復制構造函數原型,但不提供定義;
?
②類中沒有聲明,但是使用了——編譯器提供復制構造函數的原型和定義(數據成員按值傳遞);
?
③類中聲明了,使用類提供的復制構造函數。
?
?
賦值運算符:
在聲明類的時候,調用構造函數或復制構造函數。
而當類對象被聲明之后,將一個類對象賦值給另一個類對象時,才使用賦值運算符。
原型:類名&?operator=(const?類名&?);
?
①默認情況下,將使用逐成員按值傳遞;
?
②假如數據成員是另一個類對象,則在按值傳遞的時候,調用該類的賦值運算符(如果該類沒有,則使用該類的默認賦值運算符);
?
③對于指針(由new分配內存)作為數據成員時,由于構造函數需要顯式聲明,同樣,賦值運算符也需要顯式聲明以處理其情況;
?
如果要將另一個類型賦值給類對象,方法①是定義該類型作為賦值運算符的參數;方法②是使用轉換函數(之構造函數,將其他類型轉換為臨時類對象,然后通過臨時類對象賦值給類對象);
?
?
?
其他類方法:
構造函數:
特點是聲明一個新對象時調用(視情況調用默認構造函數、構造函數、或者是復制構造函數)。
?
構造函數不被派生類繼承,但派生類的構造函數會默認調用基類的構造函數。
?
如果類的數據成員使用動態內存,那么應顯式的聲明構造函數、復制構造函數、賦值運算符和析構函數。
?
?
析構函數:
①基類的析構函數應該定義為虛的,即使沒有任何內容,也至少應該有一個虛的析構函數。
?
②如果構造函數使用new來分配動態內存給數據成員,那么析構函數應該使用對應的delete來釋放內存。
?
③需要顯式的使用析構函數的情況很少,使用new定位運算符創建的類對象,是少數幾種需要顯式的調用析構函數的情況之一(因為不能通過直接delete類對象的方式,來調用析構函數)。
?
?
?
轉換:
使用一個參數就可以調用的構造函數,定義了從參數類型到類類型的轉換。
例如將一個int類型作為類構造函數的參數,那么這個類對象可以等于int類型(利用構造函數,然后調用賦值運算符)。
?
如果需要禁止這種情況發生,可以在構造函數前面加上關鍵字explicit,來禁止隱式轉換,于是只有顯式的調用對應的構造函數時,才能進行轉換。
?
將類對象轉換為其他類型的轉換函數,可以是沒有參數的類成員函數(例如operator?int());也可以是返回類型被聲明為目標類型的類成員函數(不懂)。
?
?
?
按值傳遞、按引用傳遞,返回對象和返回引用:
使用引用的好處:
①節省內存開支(不需要創建臨時對象);
?
②對于指針,如返回臨時對象的話,應顯式聲明復制構造函數,但返回引用就不用;
?
缺點:
①不能對函數內部創造的對象返回引用(因為離開函數塊時該引用的原型會被銷毀);
?
通常來說,如果是函數內部創造的對象,然后返回它,就應該使用返回對象而非返回引用。否則,應盡量使用返回引用(如果要求其不能成為左值,則加上關鍵字const);
?
?
?
使用const:
作用:
①可以確保類方法不修改對象的數據成員(在參數列表的括號后加const);
?
②確保類方法不修改調用的參數(在參數類型名前加const);
?
③確保類方法的返回值不被修改(在返回值的類型名前加cosnt);
?
?
?
?
公有繼承的考慮因素:
is-a關系:
要遵循is-a關系,如果派生類不是一種特殊的基類,則不要使用公有派生。(不懂)
感覺大概意思是說,一個類作為基類還是作為另一個類的成員對象,要看情況。有些時候適合做基類(例如派生類是基類的一種),有些時候適合做成員對象(例如派生類是基類的一部分)。
?
可以創建具有純虛函數的抽象基類,然后派生出其他類。
?
基類的指針、引用可以指向派生類對象,但不能反過來。
?
?
?
什么不能被繼承:
①構造函數:但在派生類構造函數時會自動調用基類的構造函數;
?
②析構函數:派生類析構函數也會自動調用基類的析構函數;
?
③賦值運算符:視情況而定,有時候可以使用默認的,有時候需要自定義,并顯式調用基類的賦值運算符函數(基類名::operator=(參數對象))。
?
?
賦值運算符:
①默認賦值運算符版本,將逐成員按值傳遞;
?
②派生類的賦值運算符如果是默認版本,將對基類部分調用基類的賦值運算符,對派生類新增數據成員按值傳遞;
?
③如果自定義派生類賦值運算符,那么需要顯式的聲明基類的賦值運算符以復制基類的部分;
?
④遇見new來分配內存,應自定義賦值運算符;
?
⑤默認情況下,派生類對象賦值給基類對象,相當于將派生類對象強制轉換為基類并賦值(相反則不行,只能調用參數合適的構造函數,或參數合適的賦值運算符)。
?
?
?
私有成員和保護成員:
對于派生類而言,保護成員類似公有成員;
對于外界而言,保護成員類似私有成員。
?
?
?
虛方法:
格式是函數原型(函數定義不需要)加關鍵字virtual。
①基類的析構函數需要虛方法;
?
②對于派生類需要重新定義的方法,基類使用虛方法(派生類可以不用,但用的話可以明確表示基類該方法也是虛的);
?
③使用虛方法時,受傳遞的對象所影響(按引用、指針傳遞,和按值傳遞的結果是不一樣的);
?
?
析構函數:
公有繼承的析構函數應該是虛的。
?
?
?
友元函數:
派生類不繼承友元函數,但可以顯式的調用友元函數。方法是?類名::基類友元函數?。或者是使用強制類型轉換。
?
?
?
關于使用基類方法的說明:
①某方法如果派生類沒有重新定義,則使用基類的;
?
②派生類構造函數自動調用基類的,默認調用默認構造函數,除非更改聲明調用的構造函數(例如原本是調用默認構造函數的,1個參數。改用另一個構造函數,2個參數的);
?
③一般情況下,派生類復制構造函數會自動使用基類的復制構造函數,除非自己顯式的在派生類復制構造函數使用其他構造函數;
?
④派生類的方法中,可以通過作用域解析運算符(雙冒號)顯式的調用基類的方法(前提不是私有的);
?
?
?
其他(附表):
總結
以上是生活随笔為你收集整理的(一四三)类设计回顾的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 七猫免费阅读小说怎样用(如何看待七猫中文
- 下一篇: 算法6-1:哈希函数