繼承中的虛函式與非虛函式

2021-08-14 11:44:19 字數 2616 閱讀 4963

在看公司**時, 發現了一處關於虛函式的我比較難以理解的地方,大致描述如下:

子類繼承父類, 包括繼承了虛函式和非虛函式

子類呼叫父類中的非虛函式base::printword(), 在這個非虛函式裡它又呼叫了虛函式doprintword()

實驗表明呼叫的虛函式執行的是重寫的子類虛函式。

#include 

using

namespace

std;

class base

virtual

void doprintword(const

char* c)

};class derived: public base

private:

void doprintword(const

char* c)

};int main(int argc, char *argv)

為了解決這一疑問,有必要理清虛函式和非虛函式的區別:

虛函式: 虛函式其實是一種動態繫結機制,因為在編譯時,編譯器是不知道是該呼叫父類中的虛函式還是子類中的虛函式的,而是在程式執行過程中,動態確定的。虛函式的本質是,c++編譯器透過某個**,在執行時期「間接」呼叫實際上欲繫結的函式(注意「間接」這個字眼)。這樣的**稱為虛函式表(常被稱為vtable)。每乙個「內含虛函式的類」,編譯器都會為它做出乙個虛函式表,表中的每一筆元素都指向乙個虛函式的位址。此外,編譯器當然也會為類別加上一項成員變數,是乙個指向該虛函式表的指標(常被稱為vptr)。

每乙個由此類衍生出來的物件,都有這麼乙個vptr。當我們透過這個物件呼叫虛函式,事實上是透過vptr 找到虛函式表,再找出虛函式的真正位址。

如何理解上面的間接呼叫呢?下文會詳細說以下如何間接呼叫虛函式的。

非虛函式: 非虛函式在編譯器就已經靜態確定,位址也是靜態確定的, 乙個子類 如果繼承他的父類非虛函式,那麼他們其實共享乙個非虛函式位址。

假如存在乙個非虛函式nonvirtualfunc(), 那麼base::nonvirtualfunc()和derived::nonvirtualfunc() 具有乙個相同的函式位址, 這裡的函式位址可以利用偵錯程式在除錯階段可以看出來, 是相同的。

子類在呼叫這些非虛函式和虛函式,都經歷了怎樣的過程?

乙個子類的成員函式在被呼叫時,都會預設傳入乙個引數this. 這個this關鍵字區別與函式位址, 他代表的是例項位址,乙個類中的非靜態變數、虛函式表都是通過this關鍵字進行定址的。

非虛函式的位址對編譯期來說「靜態」的,也就是函式位址在編譯期就已經確定了,例項位址對於非虛函式只是那個this指標引數。

虛函式的位址,是先到例項的位址this前面去查詢它的虛函式表所在的位址。然後從虛函式表裡取出該函式所對應的元素(虛函式表是乙個函式指標陣列)來call的。(當然乙個已知的類的虛函式表的內容 也是編譯期靜態的,但不同類的虛函式表內容不同,即執行時多型的基礎)

q1:什麼情況下可以使用this指標?

this只能在成員函式中使用。全域性函式,靜態函式都不能使用this。實際上,成員函式預設第乙個引數為t* const register this。

為什麼this指標不能在靜態函式中使用?

大家可以這樣理解,靜態函式如同靜態變數一樣,他不屬於具體的哪乙個物件,靜態函式表示了整個類範圍意義上的資訊,而this指標卻實實在在的對應乙個物件,所以this指標當然不能被靜態函式使用了。

靜態函式只能呼叫靜態函式和使用靜態變數,但是this指標所指向的變數是非靜態的,所以靜態函式中使用this指標不合理也不合法。

q2:

void

testprint(const

char* c)

對於上述的函式呼叫來實現多型,我們就嘗試用以上的知識來解釋一下:

對於非虛函式printword(), 子類在繼承時保持了該函式的函式位址不變, 子類在呼叫base::printword()時, 相當於呼叫了derived::printword()

由於乙個類的非靜態成員函式在呼叫非靜態成員函式時,會將this指標作為引數預設的傳入到函式中, 那麼該呼叫過程就類似於derived::printword(this, c);

所以在base::printword(this, c)中呼叫虛函式doprintword(),其在虛函式表中定址是基於當前this指標進行定址的,而this指標當前指向的是子類物件,那麼最終執行的虛函式是子類過載的虛函式doprintword(),最終實現了多型。

寫到這,我覺得公司原有的**雖然沒有問題,實現了多型,但是這樣的寫法確實讓人感到迷惑,不如直接呼叫子類繼承的非虛函式來的直接。

繼承中的非虛成員函式

都是在公共繼承的前提下。類成員函式包括常用的兩種。非虛函式和虛函式。非虛函式是靜態繫結,虛函式是動態繫結。繼承中的非虛函式 一般不用,都是在迷糊中錯用 這種情況下,呼叫哪個函式與指標型別有關,如果指標型別是子類型別,則呼叫子類的函式,如果是父類的型別呼叫父類的函式 1,類d會不會自己複製乙個和類a一...

虛函式,虛繼承與虛函式表

c 實現多型機制 模板技術,rtti 技術,虛函式技術,要麼是試圖做到在編譯時決議,要麼試圖做到執行時決議 虛函式 帶有 關鍵字的函式,並且不帶有 標誌的 虛繼承帶有 關鍵字的繼承,基類被稱為虛基類,會在自己物件的例項中產生虛基類指標 虛函式與菱形繼承的問題 當發生繼承時,如果派生類重寫了基類的虛函...

虛函式與繼承

學生類,派生出文科生類和理科生類,它們繼承了學生類的一些基本資訊如姓名 學號 性別,又有著自身的成員,比如說文科類有政治 歷史地理科目 理科類有化學 物理 生物科目。在錄入學生資訊時既要錄入他們的基本資訊,又要錄入他們各科的成績,所以就派生出文科類和理科類,同時對派生出來的類中的一些函式進行覆蓋 i...