C 中基類中使用虛函式與不使用的區別

2021-10-11 00:24:39 字數 2915 閱讀 8221

一、簡單區分:

" 基類中有個 void fun(){},派生類中也用void fun(){};" 

和 "基類中有個 virtual void fun(){},派生類中用void fun(){};" 它們有差別,這些差別主要體現在多型上。前者 表明基類中的函式被派生類函式覆蓋了,它們幾乎沒有關聯,在c++中就是兩個完全不同的函式,只不過恰巧名字一樣而已(但有不同的類作用域),就像在不同的作用域定義了兩個相同名字的變數。

int a; //類似基類中的fun()

namespace

;而在基類中加了 virtual 的函式表明該函式是虛函式,它用在多型裡面,派生類定義了fun()表示派生類重寫了這個函式,它們是有關聯的,當通過引用或者指標呼叫fun()時,將會進行多型解析,根據呼叫物件來決定呼叫那乙個函式。在沒有用多型的情況下,兩者就是一樣的,只不過加了 virtual 的函式執行速度可能會慢一些(視編譯器優化程度而定)。二、虛函式在c++中,使用關鍵字virtual宣告函式為虛函式。當類中定義有虛函式時,編譯器會將該類中所有虛函式的首位址儲存在一張位址表中,這張表被稱為虛函式位址表,簡稱虛表。同時,不編譯器還會在類中新增乙個隱藏資料成員,稱為虛表指標。該指標中儲存著虛表的首位址,用於記錄和查詢虛函式。

#includeclass base 

virtual void g()

virtual void h()

private:

int n;

};int main()

注意:以下彙編**全部在debug版本下,使用vc6.0進行反彙編得出的!!!!

含有虛函式的類的物件,在記憶體中大小為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在記憶體的首位址

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] // 把物件首位址返回

這裡可以看到(0x00432028)存放了三個虛函式的首位址。

三、多型

在參考文章裡,抽取一段:「最常見的用法就是宣告基類的指標,利用該指標指向任意乙個子類物件,呼叫相應的虛函式,可以根據指向的子類的不同而實現不同的方法。」 只有基類中的虛函式被過載了,用該方法才能體現c++的多型性。而且該指標,只能呼叫基類中的成員函式,以及進行了過載的虛函式(這是通過使用虛表指標實現的,因此可以理解為,該型別指標只能呼叫該類中的成員函式),而不能呼叫子類中的函式(即不能呼叫子類中不是過載的函式如下圖)。

c->g(); //這裡會報錯,因為c指標的型別為基類,只能訪問基類中的成員函式,況且,訪問子類過載的成員函式,也是通過指標進行的。

1 #include 2 

3 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 是典型的非物件導向的開發語言,但是它的確是支援類,支援類並不能說明就是支援物件導向,...