1. 程式人生 > >C++多型實現原理

C++多型實現原理

理論知識:

當類中宣告虛擬函式時,編譯器會在類中生成一個虛擬函式表。

虛擬函式表是一個儲存類成員函式指標的資料結構。

虛擬函式表是由編譯器自動生成與維護的。

virtual成員函式會被編譯器放入虛擬函式表中。

當存在虛擬函式時,每個物件中都有一個指向虛擬函式表的指標(C++編譯器給父類物件、子類物件提前佈局vptr指標;當進行howToPrint(Parent *base)函式是,C++編譯器不需要區分子類物件或者父類物件,只需要再base指標中,找vptr指標即可。)。

VPTR一般作為類物件的第一個成員。

多型的實現原理

說明1:

通過虛擬函式表指標VPTR呼叫重寫函式是在程式執行時進行的,因此需要通過定址操作才能確定真正應該呼叫的函式。而普通成員函式是在編譯時就確定了呼叫的函式。在效率上,虛擬函式的效率要低很多。

說明2:

出於效率考慮,沒有必要將所有成員函式都宣告為虛擬函式。

demo

[cpp] view plaincopyprint?

  1. #include <iostream>  
  2. using namespace std;  
  3. //多型成立的三個條件   
  4. //要有繼承  虛擬函式重寫  父類指標指向子類物件   
  5. class Parent  
  6. {  
  7. public:  
  8.     Parent(int a=0)  
  9.     {  
  10.         this->a = a;  
  11.     }  
  12.     virtual void print()  //1 動手腳  寫virtal關鍵字 會特殊處理 //虛擬函式表  
  13.     {  
  14.         cout<<"父類"<<endl;  
  15.     }  
  16.     virtual void print2()  //1 動手腳  寫virtal關鍵字 會特殊處理 //虛擬函式表  
  17.     {  
  18.         cout<<"父類"<<endl;  
  19.     }  
  20. private:  
  21.     int a;  
  22. };  
  23. class Child : public Parent  
  24. {  
  25. public:  
  26.     Child(int a = 0, int b=0):Parent(a)  
  27.     {  
  28.         this->b = b;  
  29.     }  
  30.     virtual void print()  
  31.     {  
  32.         cout<<"子類"<<endl;  
  33.     }  
  34. private:  
  35.     int b;  
  36. };  
  37. void HowToPlay(Parent *base)  
  38. {  
  39.     base->print(); //有多型發生  //2 動手腳    
  40.     //效果:傳來子類時,執行子類的print函式,傳來父類時執行父類的print函式   
  41.     //C++編譯器根本不需要區分是子類物件,還是父類物件  
  42.     //父類物件和子類物件分步有vptr指標 , ==>虛擬函式表===>函式的入口地址  
  43.     //遲繫結 (執行時的時候,c++編譯器才去判斷)  
  44. }  
  45. int main()  
  46. {  
  47.     Parent  p1; //3 動手腳 提前佈局    
  48.                 //用類定義物件的時候,C++編譯器會在物件中新增一個vptr指標   
  49.     Child   c1; //子類裡面也有一個vptr指標  
  50.     HowToPlay(&p1);  
  51.     HowToPlay(&c1);  
  52.     return 0;  
  53. }  

說明3 :C++編譯器,執行HowToPrint函式,不需要區分是子類物件還是父類物件

下面來證明vptr指標的存在。

demo

[cpp] view plaincopyprint?

  1. #include <iostream>  
  2. using namespace std;  
  3. class Parent1  
  4. {  
  5. public:  
  6.     Parent1(int a=0)  
  7.     {  
  8.         this->a = a;  
  9.     }  
  10.     void print()   
  11.     {  
  12.         cout<<"父類"<<endl;  
  13.     }  
  14. private:  
  15.     int a;  
  16. };  
  17. class Parent2  
  18. {  
  19. public:  
  20.     Parent2(int a=0)  
  21.     {  
  22.         this->a = a;  
  23.     }  
  24.     virtual void print()    
  25.     {  
  26.         cout<<"虛解構函式的父類"<<endl;  
  27.     }  
  28. private:  
  29.     int a;  
  30. };  
  31. int main()  
  32. {  
  33.     printf("sizeof(Parent):%d sizeof(Parent2):%d \n", sizeof(Parent1), sizeof(Parent2));  
  34.     // 結果是普通類大小為4,而把函式變成虛構函式之後大小為8,所以證明了這裡vptr指標的存在性  
  35.     return 0;  
  36. }