一、簡單區分:
" 基類中有個 void fun(){},派生類中也用void fun(){};"和 "基類中有個 virtual void fun(){},派生類中用void fun(){};" 它們有差別,這些差別主要體現在多型上。前者 表明基類中的函式被派生類函式覆蓋了,它們幾乎沒有關聯,在c++中就是兩個完全不同的函式,只不過恰巧名字一樣而已(但有不同的類作用域),就像在不同的作用域定義了兩個相同名字的變數。
int a; //類似基類中的fun()
namespace
;而在基類中加了 virtual 的函式表明該函式是虛函式,它用在多型裡面,派生類定義了fun()表示派生類重寫了這個函式,它們是有關聯的,當通過引用或者指標呼叫fun()時,將會進行多型解析,根據呼叫物件來決定呼叫那乙個函式。在沒有用多型的情況下,兩者就是一樣的,只不過加了 virtual 的函式執行速度可能會慢一些(視編譯器優化程度而定)。二、虛函式在c++中,使用關鍵字virtual宣告函式為虛函式。當類中定義有虛函式時,編譯器會將該類中所有虛函式的首位址儲存在一張位址表中,這張表被稱為虛函式位址表,簡稱虛表。同時,不編譯器還會在類中新增乙個隱藏資料成員,稱為虛表指標。該指標中儲存著虛表的首位址,用於記錄和查詢虛函式。
#includeclass base注意:以下彙編**全部在debug版本下,使用vc6.0進行反彙編得出的!!!!virtual void g()
virtual void h()
private:
int n;
};int main()
含有虛函式的類的物件,在記憶體中大小為8,因為含有乙個隱藏資料成員(續表指標),這個資料成員存放在物件的資料成員的首位址處,佔4個位元組!!!在初始化時,會呼叫建構函式,在該函式內,將虛表位址放入虛表指標中。如下:
主函式**(片段)實現反彙編
18: base a;
004013c8 lea ecx,[ebp-8]
// ecx中存放物件a的首位址,作為建構函式隱藏的引數,傳遞方式為thiscall
004013cb call @ilt+85(base::base) (0040105a) **(1)**
19: a.f();
004013d0 lea ecx,[ebp-8]
// ecx存放物件a的首位址,作為f()函式的隱藏的引數。
004013d3 call @ilt+140(base::f) (00401091) **(2)**
// 這裡直接呼叫函式,而沒有使用虛表指標
為什麼沒有使用虛表指標???
答:當直接使用物件呼叫自身的虛函式時,沒有必要查表訪問。這是因為已經明確呼叫的是自身成員函式,根本沒有構成多型性,查詢虛表只會畫蛇添足,降低程式執行效率。如果訪問虛表的話,為一種間接呼叫過程,需要多次定址才能完成!
**(1)**會變**主要部分:
004014c9 pop ecx // ecx存放的是物件a在記憶體的首位址這裡可以看到(0x00432028)存放了三個虛函式的首位址。004014ca mov dword ptr [ebp-4],ecx
004014cd mov eax,dword ptr [ebp-4]
004014d0 mov dword ptr [eax],offset base::`vftable' (00432028) //將虛表位址放入物件首位址中
004014d6 mov eax,dword ptr [ebp-4] // 把物件首位址返回
三、多型
在參考文章裡,抽取一段:「最常見的用法就是宣告基類的指標,利用該指標指向任意乙個子類物件,呼叫相應的虛函式,可以根據指向的子類的不同而實現不同的方法。」 只有基類中的虛函式被過載了,用該方法才能體現c++的多型性。而且該指標,只能呼叫基類中的成員函式,以及進行了過載的虛函式(這是通過使用虛表指標實現的,因此可以理解為,該型別指標只能呼叫該類中的成員函式),而不能呼叫子類中的函式(即不能呼叫子類中不是過載的函式如下圖)。
c->g(); //這裡會報錯,因為c指標的型別為基類,只能訪問基類中的成員函式,況且,訪問子類過載的成員函式,也是通過指標進行的。
1 #include 23 class a
4 10
11 virtual void fuu()
12
15 };
16 17 class b:public a
18 24
25 void fuu()
26
29 };
30 31 int main()
32
車輛類多重繼承中使用虛基類
專案3 在下面一段類的定義中,自行車類的虛基類為車輛類,機動車類的虛基類也為車輛類,電單車類的基類為自行車類和機動車類,類之間均為公有繼承。1 根據上面各類間關係的描述,補全下面程式段中空缺的 2 實現程式中宣告的成員函式,注意相應操作中的動作發生的條件不能滿足時應給出提示。資源中乙個可執行檔案,可...
C 虛基類 虛函式與純虛函式
虛基類 在說明其作用前先看一段 classa class b publica classc publica classd public b publicc void main 從 中可以看出類b c都繼承了類a的ivalue成員,因此類b c都有乙個成員變數ivalue 而類d又繼承了b c,這樣類...
C 中類的多型與虛函式的使用
類的多型特性是支援物件導向的語言最主要的特性,有過非物件導向語言開發經歷的人,通常對這一章節的內容會覺得不習慣,因為很多人錯誤的認為,支援類的封裝的語言就是支援物件導向的,其實不然,visual basic 6.0 是典型的非物件導向的開發語言,但是它的確是支援類,支援類並不能說明就是支援物件導向,...