C 多型 虛函式和純虛函式的關係

2021-09-11 23:54:58 字數 2955 閱讀 5136

c++多型意味著呼叫成員函式時,會根據呼叫函式的物件的型別來執行不同的函式;

形成多型必須具備三個條件:

1、必須存在繼承關係;

2、繼承關係必須有同名虛函式(

其中虛函式是在基類中使用關鍵字virtual宣告的函式,在派生類中重新定義基類中定義的虛函式時,會告訴編譯器不要靜態鏈結到該函式);

3、存在基類型別的指標或者引用,通過該指標或引用呼叫虛函式;

1、純虛函式宣告如下:

virtual void funtion1()=0;純虛函式一定沒有定義,純虛函式用來規範派生類的行為,即介面。包含純虛函式的類是抽象類,抽象類不能定義例項,但可以宣告指向實現該抽象類的具體類的指標或引用。

2、虛函式宣告如下:

virtual returntype functionname(parameter)虛函式必須實現,如果不實現,編譯器將報錯,錯誤提示為:

error lnk

****:

unresolved external symbol

"public: virtual void __thiscall classname::virtualfunctionname(void)"

3、對於虛函式來說,父類和子類都有各自的版本。由多型方式呼叫的時候動態繫結。

4、實現了純虛函式的子類,該純虛函式在子類中就程式設計了虛函式,子類的子類即孫子類可以覆蓋該虛函式,由多型方式呼叫的時候動態繫結。

5、虛函式是c++中用於實現多型(polymorphism)的機制。核心理念就是通過基類訪問派生類定義的函式

6、在有動態分配堆上記憶體的時候,析構函式必須是虛函式,但沒有必要是純虛的。

7、友元不是成員函式,只有成員函式才可以是虛擬的,因此友元不能是虛函式。但可以通過讓友元函式呼叫虛擬成員函式來解決友元的虛擬問題。

8、析構函式應當是虛函式,將呼叫相應物件型別的析構函式,因此,如果指標指向的是子類物件,將呼叫子類的析構函式,然後自動呼叫基類的析構函式。

動態聯編的實現機制 vtable

編譯器對每個包含虛函式的類建立乙個虛函式表vtable,表中每一項指向乙個虛函式的位址,即vtable表可以看成乙個函式指標的陣列,每個虛函式的入口位址就是這個陣列的乙個元素。

每個含有虛函式的類都有各自的一張虛函式表vtable。每個派生類的vtable繼承了它各個基類的vtable,如果基類vtable中包含某一項(虛函式的入口位址),則其派生類的vtable中也將包含同樣的一項,但是兩項的值可能不同。如果派生類中過載了該項對應的虛函式,則派生類vtable的該項指向過載後的虛函式,如果派生類中沒有對該項對應的虛函式進行重新定義,則使用基類的這個虛函式位址。

在建立含有虛函式的類的物件的時候,編譯器會在每個物件的記憶體布局中增加乙個vptr指標項,該指標指向本類的vtable。在通過指向基類物件的指標(設為bp)呼叫乙個虛函式時,編譯器生成的**是先獲取所指物件的vtb1指標,然後呼叫vtb1所指向類的vtable中的對應項(具體虛函式的入口位址)。

當基類中

沒有定義虛函式時,其長度=資料成員長度;派生類長度=自身資料成員長度+基類繼承的資料成員長度;

當基類中

定義虛函式後,其長度=資料成員長度+虛函式表的位址長度;派生類長度=自身資料成員長度+基類繼承的資料成員長度+虛函式表的位址長度。

包含乙個虛函式和幾個虛函式的類的長度增量為0。含有虛函式的類只是增加了乙個指標用於儲存虛函式表的首位址。

派生類與基類同名的虛函式在vtable中有相同的索引號(或序號)。

虛函式可以不實現(定義)。不實現(定義)的虛函式是純虛函式。

在乙個類中如果存在未定義的虛函式,那麼不能直接使用該類的例項,可以理解因為未定義 virtual 函式,其類是抽象的,無法例項化。將報錯誤:

undefined

reference to

`vtable for ***'

這和其它語言的抽象類,抽象方法是類似的——我們必須實現抽象類,否則無法例項化。(virtual 和 abstract還是有些區別的)

也就是說,如果存在以下**:

using namespace std;

class base ;

class people : base ;

};

那麼,在 main 方法中,我們不能使用 base base; 這行**,此時的 tall 沒有實現,函式表(vtable)的引用是未定義的,故而無法執行。但我們可以使用 people people; 然後

people.tall();

(&people)->tall();因為people實現或者說重寫、覆蓋了 base 的純虛方法 tall(),使其在 people 類中有了定義,函式表掛上去了,於是可以誕生例項了。

i

int main()
上述的是針對虛函式而言,普通的函式,即使我們只宣告,不定義,也不會產生上述不可用的問題。

父類的虛函式或純虛函式在子類中依然是虛函式。有時我們並不希望父類的某個函式在子類中被重寫,在 c++11 及以後可以用關鍵字 final 來避免該函式再次被重寫。

例:

#includeusing namespace std;

class base

以上程式執行結果:

this is _base

this is _base

this is _base

如果不希望乙個類被繼承,也可以使用 final 關鍵字。

格式如下:

class

class_name

final

;則該類將不能被繼承。

C 多型, 虛函式, 純虛函式

多型 不同物件接收相同的訊息產生不同的動作。多型包括 編譯時多型和 執行時多型 執行時多型是 通過繼承和虛函式來體現的。編譯時多型 運算子過載上。封裝可以隱藏實現細節,使得 模組化 繼承可以擴充套件已存在的 模組 類 它們的目的都是為了 重用。多型也有 重用的功能,還有解決專案中緊耦合的問題,提高程...

多型,虛函式,純虛函式

多型 借助虛函式,基類指標既可以使用基類 父類 的成員函式,也可以使用派生類 子類 的成員函式,它有多種形態,或多種表現方式,這就是多型 簡單說就是同一條語句可以執行不同的操作,看起來有不同表現方式,這就是多型。多型存在的三個條件 注意 派生類 子類 中的虛函式必須覆蓋 不是過載 基類 父類 中的虛...

C 多型 虛函式 純虛函式和抽象函式

多型 虛函式 純虛函式和抽象函式 多型按字面的意思就是多種形態。當類之間存在層次結構,並且類之間是通過繼承關聯時,就會用到多型。c 多型意味著呼叫成員函式時,會根據呼叫函式的物件的型別來執行不同的函式。其主要是函式的多種形態 乙個函式實現多種功能,形式是乙個乙個覆蓋。例項如下 includeusin...