運算符重載與虛函數
單目運算符
接下來都以
AClass
作為一個類例子介紹
AClass{
int var
}
- 區分后置++與前置++
AClass operator ++ ()
++前置 一般設計為返回引用 這樣的話可以將其作為左值(自然也可以作為右值,會調用該類的拷貝構造函數)++class = ...
AClass operator ++ (int)
后置++ 一般設計返回一個舊的類 獲得的是歷史版本,所含有的int
形參是用作區分類型的,並無實際含義- 由於一個__單變量__的構造函數可被視為__強制類型轉換函數__
多目運算符
-
AClass & operator (const & Aclass a){ ... }
-
因此如果該類的構造函數滿足把
int
變成這個類,你甚至可以這么寫 -
int a; AClass A; A = A + a
函數的默認形參值只能寫在聲明里,不能寫在定義里
- 對於
<<
的重載方式,定義友元函數 frend ostream & operator << (ostream & out, const ...)
- 這樣
ostream
就能訪問該類的私有成員了 - 注意!插入運算符
<<
的返回值要是這個out
的引用 {... return & out}
這樣就可以實現一直<<
插入的神奇功能(請自己思考為什么, 提示:返回引用等於又把自己拿出來用了)
虛函數
覆蓋 override 重載 overload
虛函數基本語法
巧妙的覆蓋方式
- 虛函數的聲明
virtual 函數類型 函數名(形參表){
函數內容}
- 可以在基類中聲明虛函數,則子類中的相關函數會被同樣被認為為虛函數
- 並且在創建基類指針指向一個子類時
- 調用該基類指針的這個虛函數
- 該指針會順着找到子類的這個函數並且運行
- 體現了程序運行過程中的__動態多態特性__
- 例子
class Base{
virtual void func(){
cout << "Base" << endl;
}
}
class Base1{
void func(){
cout << "Base1" << endl;
}
}
class Base2: public base{
void func(){
cout << "Base2" << endl;
}
}
void display(base * ptr)
int main(){
Base1 b1;
Base2 b2;
Base * ptr1 = b1;
Base * ptr2 = b2;
display(ptr1);
display(ptr2);
}
/*
輸出結果
Base1
Base2
*/
typeid
typeid(ptr).name()
此處ptr
為一個指針,返回這個指針的類型typeid(* ptr).name()
此處返回的是ptr
指向對象的類型- 如果你對上面的
ptr1 ptr2
進行第一種操作返回類型為base - 但是如果做第二種操作返回是base1和base2
虛析構函數
可能你想不到,析構函數也很虛
- 析構函數和構造函數是不會繼承的
- 加上析構函數在組合關系中會按拓撲序反向調用
- 那么要虛構函數的理由就是有時候你需要動態刪除由__基類指針指向的派生類__
- 沒有虛函數你就只能把指針指向的東西__當成基類__,而其本身是__派生類__,進行了析構
- 那么這樣子你就會漏去除一些內容
- 這樣很不優雅(你可以想象內存會出現什么嚴重后果)
舉個栗子!
- 比如我這么引用
Base *b = new Derived()
derived 代指派生類
- 那么我們的b一調用delete就涼涼了
delete b
- 編譯器高興地把b指向的地方當做Base刪掉了
- 仔細想想,Derived的構造函數被調用了,但是析構函數被忽略了,(原因是我換了一個指針引用)
解決方法(就是虛析構函數)
- 給基類的析構函數前面加個virtual關鍵字
- 那么這就給這個東西加上了__動態多態性!__
- 然后編譯器就會跑去先調用一下Derived類的析構函數然后再調用Base的
純虛函數
很純潔的函數
- 想想,概念都是完美的東西,那么純虛函數就是用來描述概念的
純虛函數語法
virtual 類型 函數名(參數列表) = 0
- 正如你所見,它沒有函數體(非常的純)
- 帶有純虛函數的類稱之為__抽象類__(另一個叫做__具體類__)
抽象類
概念及理念
- 為啥需要抽象類
- 由於c++沒有接口功能,那么這個純虛函數便是用作接口功能
- 底下的派生類只有將所有純虛函數全部實現才能稱之為_具體類_
- 也可以用另一種觀點來看,就是為所有派生類定義了規范
- 這是一種面向接口的設計方式,也是面向抽象類的設計
- 抽象類的設計需要非常謹慎,因為派生類需要圍繞抽象類進行設計
- 那么如果沒有設計好抽象類,那么容易帶偏派生類
幾個小規定
- 抽象類只能用作基類
- 不能聲明抽象類的對象
- 原因:抽象類中具有純虛函數,而這個函數按語法可調用,但是這個函數沒有實現,因而為了解決這個問題直接禁止了抽象類的聲明
- 構造函數不能夠是虛函數,析構函數可以是虛函數
- 可以定義抽象類的指針