裝逼利器 虛函式表

2021-10-08 14:00:35 字數 2273 閱讀 4317

我們在設計類的時候經常會遇到這樣一種情況,即同乙個方法在派生類和基類中實現不同的功能,這種行為稱為多型。

要實現這種效果,有兩個方法:

1、在派生類中重新定義基類的方法

2、使用虛函式

先看第一種方法

#include

#include

using

namespace std;

class

father};

class

son:

public father};

intmain

(void

)

在派生類裡重新定義play()之後,子類和父類的play()方法就不一樣了。但是這樣做有個缺陷,比如有乙個基類指標,讓後讓它指向乙個派生類物件

father father;

son son;

father* p[2]

=;p[0]-

>

play()

; p[1]

->

play()

;

這樣會發生什麼呢?指向派生類物件的基類指標呼叫的play()方法仍是基類的play(),也就是說這兩個方法都是基類的,並沒有實現多型。

這時候就要用到虛函式了

class

father

};

將父類的方法宣告為虛的,上面的問題就解決了。

宣告了虛方法之後,將根據基類指標指向的物件的型別呼叫該方法,而不是根據指標的型別去呼叫。

這樣做有什麼意義呢?有些時候在編譯之前,物件的型別並不確定,比如在程式執行的過程中建立了乙個物件,但你並不知道它的型別,所以編譯器必須要選擇正確的方法,這就是動態聯編。

再補充一點:宣告乙個虛析構函式只有好處沒有壞處。

father* p=

new son;..

....

delete p;

如果析構函式不是虛的,只會釋放son物件中father占用的記憶體。如果析構函式是虛的,會先呼叫~son()再呼叫 ~father()。

很多人都知道多型,虛函式,動態聯編,但是具體的原理呢,為什麼虛函式能實現動態聯編?

其實不知道也沒關係,不影響你使用虛函式,但知道了能裝逼。(末尾有彩蛋!)

要知道虛函式的原理,必須對指標有深入的了解,接下來的內容有點燒腦。

class

father

virtual

void

fun2()

virtual

void

fun3()

virtual

void

fun4()

void

fun5()

int x =10;

int y =20;

static

int z;};

int father::z =30;

intmain

(void

)

這裡有乙個很關鍵的問題,father有多大?

在32位系統上是12,64位系統是16,因為father物件中只有乙個指向虛函式表的指標和兩個資料成員x,y。其他東西都是屬於類的,並不在物件裡面。那麼知道了這一點之後,看圖:

p指向的是物件的位址,那麼怎麼把虛函式表指標取出來?

int

* vptr =

(int*)

*(p)

;//虛函式表指標

直接解引就可以了。

現在拿到了虛函式表指標,下一步怎麼辦?

接下來就可以訪問虛函式表,獲取虛函式的位址。

方法也是直接解引,那麼型別是什麼呢?函式的位址,那就是乙個函式指標,所以接下來定義乙個函式指標型別,然後強轉。

虛函式表指標,虛函式表

對c 了解的人都應該知道虛函式 virtual function 是通過一張虛函式表 virtual table 來實現的。簡稱為v table。在這個表中,主是要乙個類的虛函式的位址表,這張表解決了繼承 覆蓋的問題,保證其容真實反應實際的函式。這樣,在有虛函式的類的例項中這個表被分配在了 這個例項...

虛函式表和虛函式表的指標

有虛函式的類都有乙個虛函式表,它是實現多型的關鍵。虛函式表可以繼承,如果子類沒有重寫虛函式,那麼子類虛函式表中仍然會有該函式的位址,只不過這個位址指向的是基類的函式實現。如果子類重寫了相應的虛函式,那麼虛函式表中的位址就會改變,指向自身的函式實現。如果派生類中有自己的虛函式,那麼虛函式表中會新增該項...

虛函式之虛函式表

多型性可分為兩類 靜態多型和動態多型。函式過載和運算子過載實現的多型屬於靜態多型,動態多型性是通過虛函式實現的。每個含有虛函式的類有一張虛函式表 vtbl 表中每一項是乙個虛函式的位址,也就是說,虛函式表的每一項是乙個虛函式的指標。沒有虛函式的c 類,是不會有虛函式表的。兩張圖 簡單例子 inclu...