虛函數作為C++的重要特性,讓人又愛又怕,愛它功能強大,但又怕駕馭不好,讓它反咬一口,今天我們用CPU的角度,撕掉語法的偽裝,重新認識一下虛函數。
虛函數是C++實現面向對象設計及多態(tài)特性的重要手段。沒有虛函數,C++和C的區(qū)別就不大,都需要借助大量的“函數指針”,進行面向對象的程序設計(特別是功能擴展方面)。
有了虛函數的存在,函數指針的使用率大大降低,代碼可讀性,代碼數量都能得到大幅度的改善。
最厲害的是,C++的虛函數實現機制,幾乎同時在空間、效率上獲得了最優(yōu)解。
學習C++,虛函數是一條必經之路!
先來看兩段簡單代碼
讓我們先比較一下普通函數體與虛函數體有什么區(qū)別,顯然,兩個函數是完全一致的,虛函數跟普通函數一樣,都會夾帶一個隱藏參數this指針。所以,如你所見,虛函數在實現方面,跟普通函數沒有任何區(qū)別。
讓我們再看看調用它們的時候,會有什么不同
通過對比,大部分地方也是相同的,箭頭指的那兩條指令都是在輸入:隱藏參數 this指針。唯一的區(qū)別是,調用普通函數時,call指令的目標地址在編譯階段就確定了,也就是所謂的“靜態(tài)綁定”;但調用虛函數時,call指令只能根據rdx寄存器的值來確定函數的位置,也就是所謂的“動態(tài)綁定”。
再深入理解下這幾條指令
原來當類A有虛函數的時候,類A就會偷偷生成一個隱藏成員變量,方便起見,我們給這個隱藏變量起一個名字:V(指針類型),V存放著虛函數表的地址,根據偏移,就可以得到要執(zhí)行的vtest_1 的地址,將其存在寄存器rdx里面,隨后一條:call rdx 指令,一個虛函數的調用就完成了。如果說,類的成員函數會夾帶隱藏參數 this指針,還能接受的話,那么,我說類還會夾帶隱藏變量V,你能接受嗎?如果真的存在隱藏變量V,在哪里給V初始化呢?答案是在A的構造函數中,把V初始化成類A的虛函數表地址,如下:
盡管我沒有寫構造函數,編譯器還是會給我 生成一個默認的構造函數 ,它一定、必須要幫我完成隱藏變量V的初始化。
當然,A有派生類B的話
那么隱藏變量V會在B的構造函數中被初始化為B的虛函數表地址,從而保證A、B的虛函數相互獨立,井水不犯河水,但考慮到派生類B的構造函數,還會調用基類A的構造函數。因此,變量V一會兒會被初始化成類A的虛函數表,一會又會被初始化成類B的虛函數表,為了避免暈頭,往往會禁止在構造函數里面調用虛函數。
小結一下:
1、虛函數在函數體的實現方面跟普通函數沒有任何區(qū)別。
2、虛函數的調用需要借助類對象的隱藏變量 V(vptr)來完成,隱藏變量V(vptr)會在構造函數中被初始化成虛函數表的內存地址。
3、調用任何虛函數的套路都是一樣的,唯一的區(qū)別是要根據它們在虛函數表的位置設置正確的偏移量。
大家可以看看調用vtest_1()和調用vtest_2()的唯一區(qū)別是什么?
不得不佩服虛函數的實現方法,幾乎同時在效率的空間上得到了最優(yōu)解,因為虛函數的出現,函數指針的使用率大大降低,如果你還是被函數指針困擾的時候,或許可以考慮一下虛函數。
-
cpu
+關注
關注
68文章
11028瀏覽量
215728 -
C++
+關注
關注
22文章
2116瀏覽量
74709 -
虛函數
+關注
關注
0文章
8瀏覽量
1754
發(fā)布評論請先 登錄
C++標準編程:虛函數與內聯
關于C++中的函數重載機制
C++程序設計教程之多態(tài)性與虛函數的詳細資料說明

如何在中斷C函數中調用C++

評論