c++ 虛函數的實現機制

轉載自:http://blog.csdn.net/jiangnanyouzi/article/details/3720807


1、c++實現多態的方法

其實很多人都知道,虛函數在c++中的實現機制就是用虛表和虛指針,但是具體是怎樣的呢?從more effecive c++其中一篇文章里面可以知道:是每個類用了一個虛表,每個類的對象用了一個虛指針。具體的用法如下:

class A
{
public:
??? virtual void f();
??? virtual void g();
private:
??? int a
};

class B : public A
{
public:
??? void g();
private:
??? int b;
};

//A,B的實現省略

因為A有virtual void f(),和g(),所以編譯器為A類準備了一個虛表vtableA,內容如下:

A::f 的地址
A::g 的地址

B因為繼承了A,所以編譯器也為B準備了一個虛表vtableB,內容如下:

A::f 的地址
B::g 的地址

注意:因為B::g是重寫了的,所以B的虛表的g放的是B::g的入口地址,但是f是從上面的A繼承下來的,所以f的地址是A::f的入口地址。

然后某處有語句 B bB;的時候,編譯器分配空間時,除了A的int a,B的成員int b;以外,還分配了一個虛指針vptr,指向B的虛表vtableB,bB的布局如下:

vptr : 指向B的虛表vtableB
int a: 繼承A的成員
int b: B成員

當如下語句的時候:
A *pa = &bB;

pa的結構就是A的布局(就是說用pa只能訪問的到bB對象的前兩項,訪問不到第三項int b)

那么pa->g()中,編譯器知道的是,g是一個聲明為virtual的成員函數,而且其入口地址放在表格(無論是vtalbeA表還是vtalbeB表)的第2項,那么編譯器編譯這條語句的時候就如是轉換:call *(pa->vptr)[1](C語言的數組索引從0開始哈~)。

這一項放的是B::g()的入口地址,則就實現了多態。(注意bB的vptr指向的是B的虛表vtableB)

另外要注意的是,如上的實現并不是唯一的,C++標準只要求用這種機制實現多態,至于虛指針vptr到底放在一個對象布局的哪里,標準沒有要求,每個編譯器自己決定。我以上的結果是根據g++ 4.3.4經過反匯編分析出來的。

2、兩種多態實現機制及其優缺點

除了c++的這種多態的實現機制之外,還有另外一種實現機制,也是查表,不過是按名稱查表,是smalltalk等語言的實現機制。這兩種方法的優缺點如下:

(1)、按照絕對位置查表,這種方法由于編譯階段已經做好了索引和表項(如上面的call *(pa->vptr[1]) ),所以運行速度比較快;缺點是:當A的virtual成員比較多(比如1000個),而B重寫的成員比較少(比如2個),這種時候,B的vtableB的剩下的998個表項都是放A中的virtual成員函數的指針,如果這個派生體系比較大的時候,就浪費了很多的空間。

比如:GUI庫,以MFC庫為例,MFC有很多類,都是一個繼承體系;而且很多時候每個類只是1,2個成員函數需要在派生類重寫,如果用C++的虛函數機制,每個類有一個虛表,每個表里面有大量的重復,就會造成空間利用率不高。于是MFC的消息映射機制不用虛函數,而用第二種方法來實現多態,那就是:

(2)、按照函數名稱查表,這種方案可以避免如上的問題;但是由于要比較名稱,有時候要遍歷所有的繼承結構,時間效率性能不是很高。(關于MFC的消息映射的實現,看下一篇文章)

3、總結:

如果繼承體系的基類的virtual成員不多,而且在派生類要重寫的部分占了其中的大多數時候,用C++的虛函數機制是比較好的;

但是如果繼承體系的基類的virtual成員很多,或者是繼承體系比較龐大的時候,而且派生類中需要重寫的部分比較少,那就用名稱查找表,這樣效率會高一些,很多的GUI庫都是這樣的,比如MFC,QT

PS. 其實,自從計算機出現之后,時間和空間就成了永恒的主題,因為兩者在98%的情況下都無法協調,此長彼消;這個就是計算機科學中的根本瓶頸之所在。軟件科學和算法的發展,就看能不能突破這對時空權衡了。呵呵

何止計算機科學如此,整個宇宙又何嘗不是如此呢?最基本的宇宙之謎,還是時間和空間~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/258774.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/258774.shtml
英文地址,請注明出處:http://en.pswp.cn/news/258774.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

powerdesigner 技巧

1.修改建表腳本生成規則。如果每個表格都有相同的字段,可以如下修改: Database -> Edit Current DBMS 展開 Script -> Object -> Table -> Create 見右下的Value值,可以直接修改如下:/* tablename: %TNAME% */ create…

勒索病毒攻擊應急防范

北京時間5月12日,互聯網上出現針對Windows操作系統的勒索軟件(Wannacry)攻擊案例。勒索軟件利用此前披露的Windows SMB服務漏洞(對應微軟漏洞公告:MS17-010)攻擊手段,向終端用戶進行滲透傳播&am…

C++中虛析構函數的作用

C中的虛析構函數到底什么時候有用的,什么作用呢。 總的來說虛析構函數是為了避免內存泄露,而且是當子類中會有指針成員變量時才會使用得到的。也就說虛析構函數使得在刪除指向子類對象的基類指針時可以調用子類的析構函數達到釋放子類中堆內存的目的&…

蘋果Swift編程語言入門教程【中文版】

http://www.25pp.com/news/news_60984.html轉載于:https://www.cnblogs.com/niaowo/p/4564298.html

python正則表達式匹配aabb_Python正則表達式拆分多個匹配項

我正在嘗試將包含2個不同字符的序列的字符串拆分為多個組.如果我們假設字符是a和b,則用于分組的純文本規則為:>組包含0 a,后跟1 b>后面的所有a都包含在下一組中,除非我們在單詞末尾.例如:處理測試后,目標是分成預期的組.tests [abab,ababab,aabab…

MEF 導入(Import)和導出(Export)

前言: MEF不同于其他IOC容器(如:Castle)很重要的原因在于它使用了特性化編程模型(涉及到兩個概念:“特性”和“編程模型”)。 特性(Attribute):舉例來說就是我…

Android SimpleAdapter的參數

1.作用是ArrayList和 ListView的橋梁。這個ArrayList里邊的每一項都是一個Map<String,?>類型。 ArrayList當中的每一項 Map對象都和ListView里邊的每一項進行數據綁定一一對應。2.SimpleAdapter的構造函數&#xff1a;SimpleAdapter(Context context, List<? …

JMeter 教程匯總鏈接

http://www.360doc.com/content/14/0318/23/16361380_361732630.shtml 可以作為入門系列教程。 盡管網頁也給出了視頻鏈接&#xff0c;但是我不建議看視頻學習&#xff01; 建議直接看文字&#xff08;可以跳躍式學習&#xff0c;視頻的則是線性學習&#xff09;轉載于:https:…

C++ STL中set底層實現方式

Q&#xff1a;STL中set底層實現方式&#xff1f; 為什么不用hash&#xff1f; A: 第一個問題:set底層實現方式為RB樹&#xff08;即紅黑樹&#xff09;。 第二個問題: 首先set&#xff0c;不像map那樣是key-value對&#xff0c;它的key與value是相同的。關于set有兩種說法&…

python自動獲取天氣_用python獲取天氣數據,并作定時播報

原標題&#xff1a;用python獲取天氣數據&#xff0c;并作定時播報數據挖掘入門與實戰 公眾號&#xff1a; datadw思路1.調用和風天氣的API&#xff0c;獲取天氣數據2.用百度語音API&#xff0c;將天氣數據合成語音3.用樹莓派每天早上定時播報天氣(定時任務crontab Python腳本…

c++實現解析文件路徑

注意&#xff1a;本實現只能解析類似linux下的路徑&#xff0c;即“/data/a.txt”&#xff0c;而不能解析“c:\a.txt” 或者“c:\\a.txt”&#xff0c;但是應該很容易擴展改寫實現此功能。 FilepathParse.h #include <string> using std::string;void parseFilepath(str…

gedit搭建c開發環境

在管理外部工具中&#xff0c;創建啟動腳本 1 #!/bin/sh 2 DIR$GEDIT_CURRENT_DOCUMENT_DIR 3 NAME$GEDIT_CURRENT_DOCUMENT_NAME 4 /home/lxy/code/c/struct/run.sh ${DIR}/${NAME} 創建run.sh #!/bin/sh file$1 ext${file##*.}#C if [ $ext "c" ]; thenif [ -f $f…

Oracle數據庫入門——常用的數據字典

一、oracle數據字典主要由以下幾種視圖構成&#xff1a;1.user視圖以user_為前綴&#xff0c;用來記錄用戶對象的信息 2.all視圖以all_為前綴&#xff0c;用來記錄用戶對象的信息及被授權訪問的對象信息 3.dba視圖以dba_為前綴&#xff0c;用來記錄數據庫實例的所有對象的信息 …

一個excel文檔里復制黏貼另外表單跟著變動_利用Excel連接Power BI,實現PPT報告自動輸出...

?文/HALI就職于汽車行業戰略部門 專注汽車市場信息情報收集和分析因為工作需要&#xff0c;每月周期性的更新數據和撰寫PPT 報告成為繁重的勞動。結果是很多時間花費在數據處理上&#xff0c;真正的分析工作&#xff0c;往往只能草草收場。不能坐以待斃&#xff0c;就要想想有…

出現23.97幀率的原因

http://raytao.lofter.com/post/3d177_185a386 關于那些“格&#xff08;Frame&#xff09;”不得不說的事 今天早上&#xff0c;鄙人在社交網絡發了這一系列的問題&#xff1a;請解釋以下名詞之間的關系或差異。幀&#xff0c;格&#xff0c;幀率&#xff0c;時基&#xff0c;…

8-3建立蒙版

http://www.missyuan.com/thread-527018-1-1.html 在實際操作中&#xff0c;99.9%的蒙版都是通過選區建立的 所以選區要選好 點擊圖層調板下方的按鈕直接建立蒙版(下左圖紅色箭頭處)&#xff0c;效果等同于【圖層_圖層蒙版_顯示選區】 圖層中有了兩個對象&#xff1a;一是圖層&…

今天試了一下iscroll

感覺5和4差別還是有一點的&#xff0c;雖然不是很多&#xff0c;今天用了一下&#xff0c;感覺還是很不錯。 今天看到有人提問說如果頁面要引入多個iscroll怎么弄的問題&#xff0c;其實很簡單&#xff0c;頁面再多實例化一次就可以了。 如&#xff1a; myScroll new iScroll(…

使用ajax將數據顯示在指定位置_AJAX學習主題之一

學習主題&#xff1a;AJAX刪除用戶功能實現根據視頻中的講解&#xff0c;完成以下內容簡述刪除功能的基本思路流程點擊按鈕獲取當前元素中的用戶uid&#xff0c;向服務器發起請求&#xff0c;將uid提交到服務器刪除指定用戶&#xff0c;瀏覽器獲取瀏覽器響應結果。獨立完成刪除…

matlab 配置mex 識別vs2015

問題&#xff1a;先安裝了matlab&#xff0c;后裝了vs13和vs15,但是mex -setup時卻不能識別vs15&#xff0c;采用了兩種辦法&#xff0c;最終得以識別。解決方案&#xff1a;先采用方法&#xff1a; http://blog.csdn.net/yc461515457/article/details/51635842 &#xff0c;但…