C++中虛函數的動態綁定和多態性
目錄
-
- 靜態類型VS動態類型,靜態綁定VS動態綁定兩組概念
- 虛函數的實現機制
- 多態性
一.靜態 vs 動態
靜態類型 VS 動態類型。靜態類型指的是對象聲明的類型,在編譯器確定的。動態類型指的是對象的所指向的類型,動態類型是可以更改的,靜態類型無法更改。繼承關系會導致對象的指針和引用具有靜態類型和動態類型,因為繼承關系的存在中可能會存在類型之間的向上向下類型轉換。靜態綁定 VS 動態綁定。某特性(函數)依賴與對象的靜態類型,在編譯期確定,某特性(函數)依賴於對象的動態類型,在運行期確定。只有通過基類的引用或者指針調用虛函數時,才能發生動態綁定,如果使用對象來操作虛函數的話,仍然會采用靜態綁定的方式。因為引用或者指針既可以指向基類對象,也可以指向派生類對象的基類部分,用引用或者指針調用的虛函數
1 #include <iostream> 2 using namespace std; 3 4 class B 5 { 6 public: 7 void DoSomething(){ 8 std::cout << "B::DoSomething()" << endl; 9 } 10 virtual void vfun(){ 11 std::cout << "B::vfun()" << endl; 12 } 13 }; 14 15 class D : public B 16 { 17 public: 18 void DoSomething(){ 19 std::cout << "D::DoSomething()" << endl; 20 } 21 virtualvoid vfun(){ 22 std::cout << "D::vfun()" << endl; 23 24 } 25 }; 26 27 int main() 28 { 29 D* pd = new D(); //指針存在註意靜態類型和動態類型 30 B* pb = pd; //指正註意靜態類型和動態類型 31 pd->DoSomething(); //普通成員函數,靜態綁定靜態類型中的方法 32 pb->DoSomething(); //普通成員函數,靜態綁定靜態類型中的方法 33 34 pd->vfun(); //虛成員函數,動態綁定到動態類型中的方法 35 pb->vfun(); //虛成員函數,動態綁定到動態類型中的方法 36 return 0; 37 }
二.虛函數的的實現機制
二、C++多態性
1.多態性的定義:同一操作作用於不同的對象,可以有不同的解釋,即產生不同的執行效果。多態性有兩種,編譯時的多態,也就是函數重載;運行時多態,在系統運行時確定,是通過虛成員實現的。一般指的是後者
2.典型用例
1 #include <iostream> 2 using namespace std; 3 4 class Person 5 { 6 public: 7 virtual void print(){ 8 std::cout << "I‘m a person" << endl; 9 } 10 11 }; 12 13 class Chinese : public Person 14 { 15 public: 16 virtual void print(){ 17 std::cout << "I‘m as Chinese" << endl; 18 } 19 20 }; 21 22 class American : public Person 23 { 24 public: 25 virtual void print(){ 26 std::cout << "I‘m as American" << endl; 27 } 28 29 }; 30 31 32 //reference 33 void printPerson(Person& person){ 34 person.print(); 35 } 36 //pointer 37 void printPerson(Person* p){ 38 p->print(); 39 } 40 int main() 41 { 42 Person p; 43 Chinese c; 44 American a; 45 printPerson(p); 46 printPerson(c); 47 printPerson(a); 48 49 printPerson(&p); 50 printPerson(&c); 51 printPerson(&a); 52 53 return 0; 54 }View Code
4.多態的實現:多態是由繼承和虛函數實現的,因為虛函數是動態綁定的,依賴於調用對象(靜態類型為基類的指針和引用)的動態類型,所以根據動態類型的不同,而導致操作不同,也就是多態性。
3.虛函數的實現:簡單的說虛函數是通過虛函數表來實現的。
每個帶有虛函數的類,都會有一個虛函數表(vtbl),表中的每一項記錄它一個的虛函數的地址。實際上一個函數指針的數組。類的對象的最前面存儲虛函數表的地址。
虛函數表在類的繼承中也會繼承和重寫,當有重寫發生時,就會產生多態性。
1 #include <iostream> 2 using namespace std; 3 class Person 4 { 5 public: 6 virtual void print(){ 7 std::cout << "I‘m a person" << endl; 8 } 9 virtual void foo(){} 11 }; 12 13 class Chinese : public Person 14 { 15 public: 16 virtual void print(){ 17 std::cout << "I‘m as Chinese" << endl; 18 } 19 virtual void foo2(){} 20 }; 21 class American : public Person 22 { 23 public: 24 virtual void print(){ 25 std::cout << "I‘m as American" << endl; 26 } 27 }; 28 //reference 29 void printPerson(Person& person){ 30 person.print(); 31 } 32 //pointer 33 void printPerson(Person* p){ 34 p->print(); 35 } 36 int main() 37 { 38 Person p; 39 Chinese c; 40 American a; 41 printPerson(&p); 42 printPerson(&c); 43 printPerson(&a); 44 return 0; 45 }
Person 類的vtbl : Person::print()的地址,Person::foo()的地址
Chinese類的地址:Chinese::print()的地址,Person::foo()的地址,Person::foo1()的地址
American類的地址:American::print()的地址,Person::foo()的地址
三、總結
多態是C++的三大特性之一,非常重要,產生的條件是繼承關系,基類中存在虛成員函數,派生類override(重寫覆蓋)基類的的虛成員函數,在代碼上表現為基類對象的指針或引用調用虛成員函數,運行結果表現為實際調用各自派生類重寫的函數。
多態的核心虛成員函數是動態綁定的,即依賴於對象的動態類型。理解多態的難點是虛函數的實現機制,即虛函數表。
參考:http://blog.csdn.net/chgaowei/article/details/6427731
C++中虛函數的動態綁定和多態性