在c++中,在基類中被宣告為virtual並在在乙個或多個派生類中被重新定義的成員函式就是虛函式。基本格式如下:
virtual (return_type) (func_name) (arg)
我們可以通過指向派生類的基類指標或引用來呼叫派生類中同名覆蓋的成員函式。
如下**:
class a
究竟虛函式底層是如何實現多型呼叫的呢,那麼下面就讓我們來深度剖析下虛函式這個機制。
首先看如下兩個類:
class a
分析**:
1. void(fun)(a):首先我們定義了乙個函式指標fun,其返回值為void,引數為a*。這個函式指標用來儲存從vtbl取出的函式位址。
2. a *p=new b:接著我們new 乙個b類的例項,將其申請的記憶體單元的位址的指標儲存在a型別的指標p中,其實儲存的就是vptr指標。
3. 接著我們定義乙個long long型別來儲存vptr的值,因為我用的編譯器是64位的,指標的大小是64位,所以需要用long long型別來儲存。
4. memcpy(&lvptraddr,p,8): 該函式把p所指的8位元組記憶體裡的值複製到lvptraddr裡,複製的就是vptr指標指向的值,也就是vtbl的位址。
5.memcpy(&fun,reinterpret_cast(lvptraddr),8)
:取出vtbl中第乙個slot的內容,並存放在函式指標fun裡。由於lvptraddr是vtbl的位址,但lvptraddr不是指標,我們可以使用reinterpret_cast將其轉換成long long *指標型別。
6. func(p):呼叫剛才取出的函式位址裡面的函式,也就是b::fun()函式。
7. 如果想取出b::fun2()的話只需修改第五步的**為memcpy(&fun,reinterpret_cast(lvptraddr)+1,8)
,依次類推。
(1)非類的成員函式不能定義為虛函式,類的成員函式中靜態成員函式和建構函式也不能定義為虛函式,但可以將析構函式定義為虛函式。實際上,優秀的程式設計師常常把基類的析構函式定義為虛函式。因為,將基類的析構函式定義為虛函式後,當利用delete刪除乙個指向派生類定義的物件指標時,系統會呼叫相應的類的析構函式。而不將析構函式定義為虛函式時,只呼叫基類的析構函式。
(2)只需要在宣告函式的類體中使用關鍵字「virtual」將函式宣告為虛函式,而定義函式時不需要使用關鍵字「virtual」。
(3)當將基類中的某一成員函式宣告為虛函式後,派生類中的同名函式(函式名相同、引數列表完全一致、返回值型別相關)自動成為虛函式。
(4)如果宣告了某個成員函式為虛函式,則在該類中不能出現和這個成員函式同名並且返回值、引數個數、型別都相同的非虛函式。在以該類為基類的派生類中,也不能出現這種同名函式。
虛函式指標深入理解
程式1 include using namespace std class base1 virtual void f void virtual void g void virtual void h void private int m length int m width class base2 v...
深入理解虛函式表
在深入研究虛函式表之前,我們先思考幾個問題 1 虛函式表儲存在什麼地方 2 虛函式表中的內容是什麼時候確定的 3 虛函式表的指標什麼時候賦值 在windows系統下,虛函式表儲存在唯讀資料段 rdata 也就是說虛函式表在編譯階段就已經形成了,虛函式表指標是在建構函式中賦值的。相關解釋參考 c 虛函...
c 深入理解虛函式
為什麼使用虛函式?什麼是虛函式?虛函式是為了解決什麼問題?物件導向的三大特徵 封裝繼承 多型 1.普通虛函式 2.虛析構函式 3.純虛函式 4.抽象類 5.介面類 6.隱藏 vs 覆蓋 7.隱藏與覆蓋之間的關係 8.早繫結和晚繫結 9.虛函式表 靜態多型 vs 動態多型 靜態多型也叫做早繫結 cla...