多型和虛函式

2021-06-16 11:28:41 字數 2342 閱讀 9588

在c++

中,多型是通過虛函式實現的。

基類如果把乙個函式宣告為虛的(virtual

),就表明繼承類可以覆蓋(

override

)這個函式(從而表現不同的行為,呈現出多型性)。

對於每乙個有虛函式的類,或者覆蓋了乙個或多個基類虛函式的繼承類,可認為有乙個與之關聯的虛函式表(v-table

)。v-table

表中的每一項(

slot

)中儲存的是適當的函式指標。

c++編譯器在編譯時刻建立了所有必需的虛函式表。並且,每個虛函式表中的項都已經填充了恰當的值(指向了正確的函式入口)。

例如,下面有三個類:base

,derived

,derived2。

class base

virtual void f1() {}

virtual void f2() {}

virtual void f3() {}

base類的虛函式表如下。

slot1 – base::f1()

slot2 – base::f2()

slot3 – base::f3()

class derived: public base

//void f1() {}

void f2() {}

virtual void f3() {}

virtual void f4() {}

virtual void f5() {}

derived類的虛函式表中追加了兩項(前面的部分必須與

base

類虛函式表完全一致,包括表項的數量和位置次序),如下。

slot1 – base::f1()

slot2 – derived::f2()

slot3 – derived::f3()

slot4 – derived::f4()

slot5 – derived::f5()

注意,我有意在derived

類中不覆蓋

f1()

,這樣的話表項

1中儲存的仍然是指向

base::f1()

的函式指標。假如在

derived

類中覆蓋

f1()

的話,那麼表項

1將指向

derived::f1()。

這就是虛函式「覆蓋」的真實含義。

class derived2: public derived

void f3() {}

void f4() {}

void f5() {}

virtual void f6() {}

virtual void f7() {}

derived2類的虛函式表中又增加了兩項,如下。

slot1 – base::f1()

slot2 – derived::f2()

slot3 – derived2::f3()

slot4 – derived2::f4()

slot5 – derived2::f5()

slot6 – derived2::f6()

slot7 – derived2::f7()

現在描述一下對於虛函式的呼叫。其實已經可以看出,對於虛函式是間接呼叫的,因為它是通過虛函式表進行的。設想有乙個物件指標a

(假設型別是

base

),呼叫

a的某個函式

f(),如果

f()不是虛函式,那麼是直接呼叫的,即呼叫

base::f()

(在確定的、沒有歧義的情況下,即使可能也沒有必要採用間接呼叫技巧,使效率降低)。如果

f()是虛函式,那麼是通過虛函式表中的某個項(具體哪個表項是編譯階段完全確定了的)發起呼叫的。

為什麼不直接呼叫呢?因為編譯器不能假定這個a

指向的物件一定是

base

的例項。要知道就算乙個

derived

的例項,也可以通過上溯造型(

upcast

)被視為乙個

base

例項。 因為虛函式的原因,在

derived

類中,函式

f()完全可能被覆蓋了(從而虛函式表中的相應表項被改寫,指向

derived::f()

),所以正確的做法是通過相應的表項發起呼叫,以產生正確的行為。當然它比不上直接呼叫效率高,但是對於實現多型所要付出的不可避免的代價,這已經是很小的了。整個過程有些像變魔術,但也正達到了多型的目的(同時體現了多型的魅力)。

當然,實際沒有改寫的動作,這是邏輯上的說法。想象把繼承類的虛函式表與基類的疊在一起,那麼看起來繼承類的函式就把基類的「覆蓋」了。

虛函式和多型

虛函式的概念 在類的成員函式前加virtual關鍵字,這個成員函式稱為虛函式。虛函式重寫 當在子類的定義了乙個與父類完全相同的虛函式時,則稱子類的這個函式重寫 也稱覆蓋 了父類的這個虛函式。include using namespace std class person public virtual...

虛函式和多型

pragma once 普通飛機 class plane include plane.h include using namespace std void plane fly void plane land pragma once include plane.h 直公升飛機 class jet pu...

虛函式和多型

定義 類的成員函式前面加virtual關鍵字 虛函式重寫 子類定義了乙個與父類完全角同的虛函式,子類的函式重寫 覆蓋 父類的虛函式 隱藏 作用域不同,注意 虛函式和虛繼承關鍵字一樣,但意義完全不同 多型 當使用基類的指標或引用呼叫重寫的虛函式時,當指向父類呼叫的就是父類的虛函式,指向子類呼叫的就是子...