多型」的關鍵在於通過基類指標或引用呼叫乙個虛函式時,編譯時不確定到底呼叫的是基類還是派生類的函式,執行時才確定。
#include
using namespace std;
class a
virtual void func2() {}
};class b : public a
};int main()
在 32 位編譯模式下,程式的執行結果是:
8, 12
如果將程式中的 virtual 關鍵字去掉,輸出結果變為:
4, 8
a * p = new b() 實現多型
對比發現,有了虛函式以後,物件所占用的儲存空間比沒有虛函式時多了 4 個位元組。實際上,任何有虛函式的類及其派生類的物件都包含這多出來的 4 個位元組,這 4 個位元組就是實現多型的關鍵——它位於物件儲存空間的最前端,其中存放的是虛函式表的位址。
每程式設計客棧乙個有虛函式的類(或有虛函式的類的派生類)都有乙個虛函式表,該類的任何物件中都放著該虛函式表的指標(可以認為這是由編譯器自動新增到建構函式中的指令完成的)。
沒有覆蓋時的子類,可以看到子類的虛函式表的前面是基類離得虛函式
有覆蓋就是
子類物件位址為什麼能賦值給父類物件指標?
因為,子類物件位址賦值給父類物件指標,父類物件指標就指向了子類的物件空間,父類操作子類的範圍是有限制的,只能操作到子類中父類的範圍。
基類和子類各有自己的虛www.cppcns.com函式表vtbl;不管是基類還是子類例項都會在其記憶體的開頭自動創物件即虛函式表指標vptr, 用來訪問所在類的虛函式表
想要實現多型,需要動態繫結,需要父類的指標或父類的引用
父類方法為虛方法,子類覆蓋父類的虛方法,才能達到多型
子類中父類沒有的方法,父類指標也無法訪問到,父類指標只能訪問到父類自己有的範圍
子類要覆蓋父類的方法,就是要函式名引數都必須一樣才叫覆蓋
再看乙個例子
class a ;
class b : public a ;
class c: public b ;
子類繼承父類,子類中有父類的同名方法,訪問的是子類的方法,子類會隱藏父類所有的同名方法,即使父類有乙個同名的xspodurilt引數不同的方法也是如此。
多重繼承(無虛函式覆蓋)
下面,再讓我們來看看多重繼承中的情況,假設有下面這樣乙個類的繼承關係。注意:子類並沒有覆蓋父類的函式。
對於子類例項中的虛函式表,是下面這個樣子:
我們可以看到:
1) 每個父類都有自己的虛表。
2) 子類的成員函式被放到了第乙個父類的表中。(所謂的第乙個父類是按照宣告順序來判斷的)
這樣做就是為了解決不同的父類型別的指標指向同乙個子類例項,而能夠呼叫到實際的函式。
多重繼承(有虛函式覆蓋)
下面我們再來看看,如果發生虛函式覆蓋的情況。
下圖中,我們在子類中覆蓋了父類的f()函式。
下面是對於子類例項中的虛函式表的圖:
我們可以看見,三個父類虛函式表中的f()的位置被替換成了子類的函式指標。這樣,我們就可以任一靜態型別的父類來指向子類,並呼叫子類的f()了。
任何妄圖使用父類指標想呼叫子類中的未覆蓋父類的成員函式的行為都會被編譯器視為非法,
本文標題: c++ 虛函式及虛函式表詳解
本文位址: /ruanjian/c/434739.html
虛函式及虛函式表
虛函式及虛函式表 首先,我們要分清三大概念 過載 重寫 覆蓋 和重定義 一.函式過載 1 在相同的作用域內 無繼承關係,只在乙個類內進行宣告 2 進行多個函式宣告 3 多個函式的函式名相同,引數列表不同 可以是型別不同 引數型別不同 傳參順序不同 4 函式的返回值型別可以相同,可以不同。不能僅依靠函...
C 虛函式表及虛函式執行原理詳解
為了實現虛函式,c 使用了虛函式表來達到延遲繫結的目的。虛函式表在動態 延遲繫結行為中用於查詢呼叫的函式。儘管要描述清楚虛函式表的機制會多費點口舌,但其實其本身還是比較簡單的。首先,每個包含虛函式的類 或者繼承自的類包含了虛函式 都有乙個自己的虛函式表。這個表是乙個在編譯時確定的靜態陣列。虛函式表包...
C 虛函式和虛函式表詳解
在講解虛函式之前需要先區分一下以下定義 過載,重寫,重定義 過載 同乙個類中函式名相同,函式的引數列表不相同的兩個及兩個以上的函式就是函式過載。注意 函式的返回值不能作為函式是否過載的依據。重寫 是在子類繼承父類的時候,對父類的虛函式進行了覆蓋。重寫會使程式發生動態聯編,產生多型。重定義 是在子類繼...