1,函數重寫回顧: 1,父類中被重寫的函數依然會繼承給子類; 2,子類中重寫的函數將覆蓋父類中的函數; 1,重寫父類當中提供的函數是因為父類當中提供的這個函數版本不能滿足我們的需求,因此我們要重寫; 2,期望只要是子類對象,則調用子類當中的版本,而不是父類當中定義的函數版本; 3,通過作用域分辨符( ...
1,函數重寫回顧:
1,父類中被重寫的函數依然會繼承給子類;
2,子類中重寫的函數將覆蓋父類中的函數;
1,重寫父類當中提供的函數是因為父類當中提供的這個函數版本不能滿足我們的需求,因此我們要重寫;
2,期望只要是子類對象,則調用子類當中的版本,而不是父類當中定義的函數版本;
3,通過作用域分辨符(::)可以訪問到父類中的函數;
1,代碼示例:
Child c; Parent* p = &c; c.Parent::print(); // 從父類中繼承;I'm Parent. c.print(); // 在子類中重寫;I'm Child. p->print(); // 父類中定義;I'm Parent.不是我們期望的版本,因為 p 指向了子類對象,期望調用子類版本
2,面相對象中期望的行為:
1,根據實際的對象類型判斷如何調用重寫函數;
1,而不是根據指針類型(編譯器預設的安全行為);
2,父類指針(引用)指向:
1,父類對象,則調用父類中定義的函數;
2,子類對象,則調用子類中定義的重寫函數;
3,面向對象中的多態的概念:
1,根據實際的對象類型決定函數調用的具體目標;
1,相同的行為方式可能導致不同的行為結果,即產生了多種形態行為,即多態;
2,同樣的調用語句在實際運行時有多種不同的表現形態;
1,同一行語句展現了多種不同的表現形態,多態本質;
4,C++ 語言直接支持多態的概念:
1,通過使用 virtual 關鍵字對多態進行支持;
1,什麼時候用 virtual ?
2,定義類的時候,覺得某一個函數在後續被繼承的過程當中,有可能被重寫,就是用 virtual 關鍵字修飾這個函數;
2,被 virtual 聲明的函數被重寫後具有多態特性;
1,函數名和參數都必須一樣,若函數名相同但參數不同,這是同名覆蓋;
3,被 virtual 聲明的函數叫做虛函數(因為 virtual 的意思就是虛擬的);
1,虛函數被繼承後依然是虛函數,不用再被 virtual 修飾;
5,多態的初體驗編程實驗:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Parent 7 { 8 public: 9 virtual void print() // 這個函數可能被繼承的子類重寫,所以加上virtual 關鍵字來修飾它,稱為虛函數,實現多態; 10 { 11 cout << "I'm Parent." << endl; 12 } 13 }; 14 15 class Child : public Parent 16 { 17 public: 18 void print() // 雖然沒有寫 virtual 關鍵字,但是由於繼承的關係,它就是虛函數;一般工程中沒必要在子類中寫 virtual; 19 { 20 cout << "I'm Child." << endl; 21 } 22 }; 23 24 void how_to_print(Parent* p) 25 { 26 p->print(); // 希望展現多態行為; 27 } 28 29 int main() 30 { 31 Parent p; 32 Child c; 33 34 how_to_print(&p); // 期望列印: I'm Parent. 實際列印:I'm Parent. 35 how_to_print(&c); // 期望列印: I'm Child. 實際列印:I'm Child. 36 37 return 0; 38 }
6,多態意義:
1,在程式運行過程中展現出動態的特性;
1,編譯時無法決定究竟調用哪一個版本的實現;
2,函數重寫必須多態實現,否則沒有意義;
1, C++ 後續語言(Java、C#)中,只要是重寫,一定是虛函數,不需要顯示聲明 virtual 關鍵字;
3,多態是面向對象組件化程式設計的基礎特性;
1,後續學習中多態特性會被變著花樣玩兒,特別是設計模式中絕大多數模式都和多態相關;
7,理論中的概念:
1,靜態聯編:
1,在程式的編譯期間就能確定具體的函數調用;
1,如函數重載;
2,動態聯編(多態):
1,在程式實際運行後才能確定具體的函數調用;
1,如函數重寫;
8,動態聯編與靜態聯編實例分析:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Parent 7 { 8 public: 9 virtual void func() 10 { 11 cout << "void func()" << endl; 12 } 13 14 virtual void func(int i) 15 { 16 cout << "void func(int i) : " << i << endl; 17 } 18 19 virtual void func(int i, int j) 20 { 21 cout << "void func(int i, int j) : " << "(" << i << ", " << j << ")" << endl; 22 } 23 }; 24 25 class Child : public Parent 26 { 27 public: 28 void func(int i, int j) 29 { 30 cout << "void func(int i, int j) : " << i + j << endl; 31 } 32 33 void func(int i, int j, int k) // 子類同名覆蓋父類當中的函數,重載同一作用域當中的函數; 34 { 35 cout << "void func(int i, int j, int k) : " << i + j + k << endl; 36 } 37 }; 38 39 void run(Parent* p) 40 { 41 p->func(1, 2); // 展現多態的特性,動態聯編 42 } 43 44 int main() 45 { 46 Parent p; 47 48 p.func(); // 靜態聯編 49 p.func(1); // 靜態聯編 50 p.func(1, 2); // 靜態聯編 51 52 cout << endl; 53 54 Child c; 55 56 c.func(1, 2); // 靜態聯編 57 58 cout << endl; 59 60 run(&p); 61 run(&c); 62 63 return 0; 64 }
9,多態編程實驗:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Boss 7 { 8 public: 9 int fight() 10 { 11 int ret = 10; 12 13 cout << "Boss::fight() : " << ret << endl; 14 15 return ret; 16 } 17 }; 18 19 class Master 20 { 21 public: 22 virtual int eightSwordKill() 23 { 24 int ret = 8; 25 26 cout << "Master::eightSwordKill() : " << ret << endl; 27 28 return ret; 29 } 30 }; 31 32 class NewMaster : public Master 33 { 34 public: 35 int eightSwordKill() // 重寫八劍齊飛 36 { 37 int ret = Master::eightSwordKill() * 2; 38 39 cout << "NewMaster::eightSwordKill() : " << ret << endl; 40 41 return ret; 42 } 43 }; 44 45 void field_pk(Master* master, Boss* boss) 46 { 47 int k = master->eightSwordKill(); // 賦值相容性加上函數重載,根據實際的對象調用函數; 48 int b = boss->fight(); 49 50 if( k < b ) 51 { 52 cout << "Master is killed..." << endl; 53 } 54 else 55 { 56 cout << "Boss is killed..." << endl; 57 } 58 } 59 60 int main() 61 { 62 Master master; 63 Boss boss; 64 65 cout << "Master vs Boss" << endl; 66 67 field_pk(&master, &boss); 68 69 cout << "NewMaster vs Boss" << endl; 70 71 NewMaster newMaster; 72 73 field_pk(&newMaster, &boss); 74 75 return 0; 76 }
10,小結:
1,函數重寫只可能發生在父類與子類之間;
2,根據實際對象的類型確定調用的具體函數;
3,virtual 關鍵字是 C++ 中支持多態的唯一方式;
4,被重寫的虛函數課表現出多態的特性;
5,虛函數和多態的關係:
1,多態是面向對象理論當中的一個概念,它和具體的程式設計語言是沒有關係的,也就是說多態指的僅僅是相同的行為方式,不同的行為結果;
2,這種多態的表現形式在 C++ 中由虛函數來實現;