深刻解析C++中的虛函數與多態。本站提示廣大學習愛好者:(深刻解析C++中的虛函數與多態)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻解析C++中的虛函數與多態正文
1.C++中的虛函數
C++中的虛函數的感化重要是完成了多態的機制。關於多態,簡而言之就是用父類型其余指針指向其子類的實例,然後經由過程父類的指針挪用現實子類的成員函數。這類技巧可讓父類的指針有“多種形狀”,這是一種泛型技巧。所謂泛型技巧,說白了就是試圖應用不變的代碼來完成可變的算法。好比:模板技巧,RTTI技巧,虛函數技巧,要末是試圖做到在編譯時決定,要末試圖做到運轉時決定。
對C++ 懂得的人都應當曉得虛函數(Virtual Function)是經由過程一張虛函數表(Virtual Table)和一個指向虛函數表的指針(vptr)來完成的。虛函數表,簡稱為vtbl,虛函數表表對完成多態起著相當主要的感化。在這個表中,重要保留了一個類中的虛函數的地址,這張表處理了繼續、籠罩的成績,包管其內容能真實反響現實的函數。每個包括虛函數的類的實例都包括一個cptr指針,指向虛函數表的首地址。我們可以經由過程這個指針找到要拜訪的虛函數的,完成虛函數的挪用重要包含:找到虛函數表的首地址(vptr),經由過程cptr找到要應用虛函數地址,挪用虛函數。那末應用虛函數年夜家總要斟酌效力的成績,現實上為了進步效力,C++的編譯器是包管虛函數表的指針存在於對象實例中最後面的地位,這是為了包管取到虛函數表的有最高的機能,這意味著我們經由過程對象實例的地址獲得這張虛函數表,然後經由過程遍歷表便可以找到個中的虛函數的地址,然後挪用響應的函數。無妨看看上面的代碼:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};
typedef void(*Fun)(void);
int main()
{
Base b;
Fun pFun = NULL;
cout << "虛函數表地址:" << (int*)(&b) << endl;
cout << "虛函數表 — 第一個函數地址:" << (int*)*(int*)(&b) << endl;
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
return 0;
}
經由過程這個示例,可以看到,經由過程強行把&b轉成int *,獲得虛函數表的地址(vptr),然後,再次取址便可以獲得第一個虛函數的地址了,也就是Base::f(),這在下面的法式中獲得了驗證(把int* 強迫轉成了函數指針)。經由過程這個示例,我們便可以曉得假如要挪用Base::g()和Base::h(),其代碼以下:
(Fun)*((int*)*(int*)(&b)+0); // Base::f()
(Fun)*((int*)*(int*)(&b)+1); // Base::g()
(Fun)*((int*)*(int*)(&b)+2); // Base::h()
可以看看虛函數表的圖是怎樣畫的:
年夜家都曉得,多態是經由過程繼續完成的,那末我們要說說虛函數繼續的成績。繼續就觸及到了虛函數的籠罩了,現實上不被籠罩的虛函數和多態又有甚麼接洽呢?這裡我們評論辯論有籠罩的虛函數表是甚麼樣的,假定存鄙人面的繼續關系:
看看虛函數表現甚麼樣的:
可以發明,Base::f()被籠罩了,如許若把Derive的實例賦值給一個基類Base指針pBase,經由過程pBase->f();則拜訪的是子類中的f()也就是完成了多態。那末虛函數表中的內容究竟是怎樣樣的呢?可以看看上面的四句話就會明確!
1.虛函數依照其聲明次序放於表中。
2.父類的虛函數在子類的虛函數後面。
3.籠罩的f()函數被放到了虛表華夏來父類虛函數的地位。
4.沒有被籠罩的函數照舊。
2.用虛函數完成多態
看看上面的多態的代碼:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void Print()
{
cout<<"Base::Print()"<<endl;
}
};
class Derive : public Base
{
public:
virtual void Print()
{
cout<<"Derive::Print()"<<endl;
}
};
int main()
{
Derive derive;
Base *pBase = &derive;
pBase->Print();
return 0;
}
//多態代碼
完成虛函數的代碼,必定要切記:必定是基類的指針指向子類的對象的地址。起首試著懂得一下用虛函數完成多態的道理,假如其實沒懂得為何虛函數能完成多態,又為何如許完成多態,上彀再搜一搜相干的材料!!!