物件導向程式設計的基本觀點是用程式來**大千世界,這使得它的各種根本特性非常人性化,如封裝、繼承、多型等等,而虛函式就是c++中實現多型性的主將。為了實現多型性,c++編譯器也革命性地提供了動態聯編(或叫晚**)這一特徵。
虛函式亦是mfc程式設計的關鍵所在,mfc程式設計主要有兩種方法:一是響應各種訊息,進行對應的訊息處理。二就是過載並改寫虛函式,來實現自己的某些要求或改變系統的某些預設處理。
虛函式的地位是如此的重要,對它進行窮根究底,力求能知其然並知其所以然 對我們程式設計能力的提高大有好處。下面且聽我道來。
多型性和動態聯編的實現過程分析
一、基礎略(限於篇幅,請參閱相應的c++書籍):
1、多型性:使用基礎類的指標動態呼叫其派生類中函式的特性。
2、動態聯編:在執行階段,才將函式的呼叫與對應的函式體進行連線的方式,又叫執行時聯編或晚**。
二、過程描述:
1、編譯器發現乙個類中有虛函式,編譯器會立即為此類生成虛函式表 vtable(後面有對vtable的分析)。虛函式表的各表項為指向對應虛函式的指標。
2、編譯器在此類中隱含插入乙個指標vptr(對vc編譯器來說,它插在類的第乙個位置上)。
有乙個辦法可以讓你感知這個隱含指標的存在,雖然你不能在類中直接看到它,但你可以比較一下含有虛函式時的類的尺寸和沒有虛函式時的類的尺寸,你能夠發現,這個指標確實存在。
3、在呼叫此類的建構函式時,在類的建構函式中,編譯器會隱含執行vptr與vtable的關聯**,將vptr指向對應的vtable。這就將類與此類的vtable聯絡了起來。
4、在呼叫類的建構函式時,指向基礎類的指標此時已經變成指向具體的類的this指標,這樣依靠此this指標即可得到正確的vtable,從而實現了多型性。在此時才能真正與函式體進行連線,這就是動態聯編。
三、vtable 分析:
分析1:虛函式表包含此類及其父類的所有虛函式的位址。如果它沒有過載父類的虛函式,vtable中對應表項指向其父類的此函式。反之,指向過載後的此函式。
分析2:虛函式被繼承後仍舊是虛函式,虛函式非常嚴格地按出現的順序在 vtable 中排序,所以確定的虛函式對應 vtable 中乙個固定的位置n,n是乙個在編譯時就確定的常量。所以,使用vptr加上對應的n,就可得到對應函式的入口位址。
四、編譯器呼叫虛函式的彙編碼(參考think in c++):
push funparam ;先將函式引數壓棧
push si ;將this指標壓棧,以確保在當前類上操作
mov bx,word ptr[si] ;因為vc++編譯器將vptr放在類的第乙個位置上,所以bx內為vptr
call word ptr[bx+n] ;呼叫虛函式。n = 所呼叫的虛函式在對應 vtable 中的位置
純虛函式:
一、引入原因:
1、為了方便使用多型特性,我們常常需要在基類中定義虛函式。
2、在很多情況下,基類本身生成物件是不合情理的。例如,動物作為乙個基類可以派生出老虎、孔雀等子類,但動物本身生成物件明顯不合常理。
為了解決上述問題,引入了純虛函式的概念,將函式定義為純虛函式(方法:virtual returntype function()= 0;),則編譯器要求在派生類中必須予以過載以實現多型性。同時含有純虛函式的類稱為抽象類,它不能生成物件。這樣就很好地解決了上述兩個問題。
二、純虛函式實質:
1、類中含有純虛函式則它的vtable表不完全,有乙個空位,所以,不能生成物件(編譯器絕對不允許有呼叫乙個不存在函式的可能)。在它的派生類中,除非過載這個函式,否則,此派生類的vtable表亦不完整,亦不能生成物件,即它也成為乙個純虛基類。
虛函式與構造、析構函式:
1、建構函式本身不能是虛函式;並且虛機制在建構函式中不起作用(在建構函式中的虛函式只會呼叫它的本地版本)。
想一想,在基類建構函式中使用虛機制,則可能會呼叫到子類,此時子類尚未生成,有何後果!?。
2、析構函式本身常常要求是虛函式;但虛機制在析構函式中不起作用。
若類中使用了虛函式,析構函式一定要是虛函式,比如使用虛擬機制呼叫delete,沒有虛擬的析構函式,怎能保證delete的是你希望delete的物件。
虛機制也不能在析構函式中生效,因為可能會引起呼叫已經被delete掉的類的虛函式的問題。
物件切片:
向上對映(子類被對映到父類)的時候,會發生子類的vtable 完全變成父類的vtable的情況。這就是物件切片。
原因:向上對映的時候,介面會變窄,而編譯器絕對不允許有呼叫乙個不存在函式的可能,所以,子類中新派生的虛函式的入口在vtable中會被強行「切」掉,從而出現上述情況。
虛函式使用的缺點
優點講了一大堆,現在談一下缺點,虛函式最主要的缺點是執行效率較低,看一看虛函式引發的多型性的實現過程,你就能體會到其中的原因。
希望通過以上內容的介紹,能夠給你帶來幫助。
詳細介紹C 中的虛函式和動態聯編
物件導向程式設計的基本觀點是用程式來 大千世界,這使得它的各種根本特性非常人性化,如封裝 繼承 多型等等,而虛函式就是c 中實現多型性的主將。為了實現多型性,c 編譯器也革命性地提供了動態聯編 或叫晚 這一特徵。虛函式亦是mfc程式設計的關鍵所在,mfc程式設計主要有兩種方法 一是響應各種訊息,進行...
詳細介紹C 中的虛函式和動態聯編
物件導向程式設計的基本觀點是用程式來 大千世界,這使得它的各種根本特性非常人性化,如封裝 繼承 多型等等,而虛函式就是c 中實現多型性的主將。為了實現多型性,c 編譯器也革命性地提供了動態聯編 或叫晚 這一特徵。虛函式亦是mfc程式設計的關鍵所在,mfc程式設計主要有兩種方法 一是響應各種訊息,進行...
靜態聯編(函式過載)和動態聯編(虛函式)
一 靜態聯編 定義 由於函式過載,編譯器必須檢視函式引數以及函式名就能確定使用哪個函式 這種c c 編譯器可以在編譯過程中完成的聯編,被稱為靜態聯編 函式過載 在同一作用域中,可以有一組具有相同函式名,不同引數列表的函式,這組函式被稱為過載函式 二 動態聯編 定義 使用哪個函式是不能在編譯時確定的,...