C++多型實現原理
阿新 • • 發佈:2019-02-08
理論知識:
當類中宣告虛擬函式時,編譯器會在類中生成一個虛擬函式表。
虛擬函式表是一個儲存類成員函式指標的資料結構。
虛擬函式表是由編譯器自動生成與維護的。
virtual成員函式會被編譯器放入虛擬函式表中。
當存在虛擬函式時,每個物件中都有一個指向虛擬函式表的指標(C++編譯器給父類物件、子類物件提前佈局vptr指標;當進行howToPrint(Parent *base)函式是,C++編譯器不需要區分子類物件或者父類物件,只需要再base指標中,找vptr指標即可。)。
VPTR一般作為類物件的第一個成員。
多型的實現原理
說明1:
通過虛擬函式表指標VPTR呼叫重寫函式是在程式執行時進行的,因此需要通過定址操作才能確定真正應該呼叫的函式。而普通成員函式是在編譯時就確定了呼叫的函式。在效率上,虛擬函式的效率要低很多。
說明2:
出於效率考慮,沒有必要將所有成員函式都宣告為虛擬函式。
demo
[cpp] view plaincopyprint?
- #include <iostream>
- using namespace std;
- //多型成立的三個條件
- //要有繼承 虛擬函式重寫 父類指標指向子類物件
- class Parent
- {
- public:
- Parent(int a=0)
- {
- this->a = a;
- }
- virtual void print() //1 動手腳 寫virtal關鍵字 會特殊處理 //虛擬函式表
- {
- cout<<"父類"<<endl;
- }
- virtual void print2() //1 動手腳 寫virtal關鍵字 會特殊處理 //虛擬函式表
- {
- cout<<"父類"<<endl;
- }
- private:
- int a;
- };
- class Child : public Parent
- {
- public:
- Child(int a = 0, int b=0):Parent(a)
- {
- this->b = b;
- }
- virtual void print()
- {
- cout<<"子類"<<endl;
- }
- private:
- int b;
- };
- void HowToPlay(Parent *base)
- {
- base->print(); //有多型發生 //2 動手腳
- //效果:傳來子類時,執行子類的print函式,傳來父類時執行父類的print函式
- //C++編譯器根本不需要區分是子類物件,還是父類物件
- //父類物件和子類物件分步有vptr指標 , ==>虛擬函式表===>函式的入口地址
- //遲繫結 (執行時的時候,c++編譯器才去判斷)
- }
- int main()
- {
- Parent p1; //3 動手腳 提前佈局
- //用類定義物件的時候,C++編譯器會在物件中新增一個vptr指標
- Child c1; //子類裡面也有一個vptr指標
- HowToPlay(&p1);
- HowToPlay(&c1);
- return 0;
- }
說明3 :C++編譯器,執行HowToPrint函式,不需要區分是子類物件還是父類物件
下面來證明vptr指標的存在。
demo
[cpp] view plaincopyprint?
- #include <iostream>
- using namespace std;
- class Parent1
- {
- public:
- Parent1(int a=0)
- {
- this->a = a;
- }
- void print()
- {
- cout<<"父類"<<endl;
- }
- private:
- int a;
- };
- class Parent2
- {
- public:
- Parent2(int a=0)
- {
- this->a = a;
- }
- virtual void print()
- {
- cout<<"虛解構函式的父類"<<endl;
- }
- private:
- int a;
- };
- int main()
- {
- printf("sizeof(Parent):%d sizeof(Parent2):%d \n", sizeof(Parent1), sizeof(Parent2));
- // 結果是普通類大小為4,而把函式變成虛構函式之後大小為8,所以證明了這裡vptr指標的存在性
- return 0;
- }