青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

以題論道----關(guān)于虛函數(shù)的一些解讀

                                    peakflys原創(chuàng)作品,轉(zhuǎn)載請(qǐng)注明源作者和源鏈接!
    virtual function是很多公司面試題的重點(diǎn)考察內(nèi)容,雖然對(duì)于C++而言這是一個(gè)老生常談的話(huà)題了,但是工作中我發(fā)現(xiàn)還是有很多人理解的不透徹。
    先看下面的一個(gè)例子:
/**
 *\brief virtual function test case
 *\author peakflys
 *\date Sun Dec  1 14:52:47 CST 2013
 */
#include <iostream>
using namespace std;
class Base
{
public:
    virtual void print(const int a = 10) {cout<<"Base: "<<a<<endl;}
};
class Derive : public Base
{
public:
    virtual void print(const int a = 100) {cout<<"Derive: "<<a<<endl;}
};
int main()
{
    Base *pb = new Derive;
    pb->print();
    Base& rb = *pb;
    rb.print();
    Derive d;
    d.print();
    Base *pbb = &d; 
    pbb->print();
    Base& rbb = d;
    rbb.print();
    Base b;
    b.print();
    Derive *pd = (Derive*)&b;
    pd->print();
    Derive& rd = *(Derive*)&b;
    rd.print();
    delete pb; 
    return 0;
}
你認(rèn)為運(yùn)行后的結(jié)果是什么呢?
下面是在我機(jī)器上的運(yùn)行結(jié)果(Linux dev 2.6.32,gcc (GCC) 4.8.1)
Derive: 10
Derive: 10
Derive: 100
Derive: 10
Derive: 10
Base: 10
Base: 100
Base: 100
上面例子主要考察的內(nèi)容有四塊:虛函數(shù)的執(zhí)行、引用和指針的關(guān)系、函數(shù)調(diào)用過(guò)程、類(lèi)型強(qiáng)轉(zhuǎn)后的行為。如果你能答對(duì)所有的結(jié)果,下面的內(nèi)容可以略過(guò)。
下面我們來(lái)一一回顧一下所涉及到的這四塊內(nèi)容。
1、虛函數(shù)的運(yùn)行機(jī)理:
虛函數(shù)是C++實(shí)現(xiàn)多態(tài)性的必要手段,它在運(yùn)行時(shí)刻才決定具體該調(diào)用哪個(gè)函數(shù)。對(duì)于虛函數(shù)的完整細(xì)節(jié)實(shí)現(xiàn)標(biāo)準(zhǔn)并未給出,但是大多數(shù)編譯器廠商,包括GCC、VS的常見(jiàn)實(shí)現(xiàn)都是在含有虛函數(shù)的類(lèi)對(duì)象起始地址增加一個(gè)虛表指針,虛表指針指向的數(shù)組空間稱(chēng)之為虛表,這個(gè)數(shù)組包含了類(lèi)對(duì)象的所有虛函數(shù)地址。詳細(xì)內(nèi)容大家可以參看《Inside The C++ Object Model》的Function語(yǔ)義學(xué)(注:這本書(shū)里有部分結(jié)論和例子運(yùn)行同現(xiàn)在主流編譯器的實(shí)現(xiàn)有出入)。
2、引用的行為
在常見(jiàn)的編譯器中,引用一般都是通過(guò)指針來(lái)實(shí)現(xiàn)的,它同指針的區(qū)別就是它比指針有更多的約束,使用上有更多的限制。
3、虛函數(shù)的調(diào)用過(guò)程:
虛函數(shù)的調(diào)用過(guò)程通常是以下三個(gè)步驟:
①、參數(shù)壓棧
②、從虛表指針指向的虛表中找出函數(shù)的地址
③、調(diào)用函數(shù)。
這些操作都是在編譯時(shí)期就確定的,所不同的是運(yùn)行時(shí)刻對(duì)象不同,其對(duì)應(yīng)的虛表中函數(shù)地址自然也就是運(yùn)行時(shí)真實(shí)對(duì)象的函數(shù),這也就是虛函數(shù)實(shí)現(xiàn)的本質(zhì)。
而這個(gè)過(guò)程中,參數(shù)的入棧是對(duì)象無(wú)關(guān)的,而且是在編譯時(shí)期就確定下來(lái)的。所以上面例子中所有指針和引用所調(diào)用函數(shù)的參數(shù),都是指針和引用本身類(lèi)型對(duì)應(yīng)的函數(shù)默認(rèn)參數(shù),同運(yùn)行時(shí)刻他們真實(shí)指向的對(duì)象內(nèi)存無(wú)關(guān)。
4、類(lèi)型強(qiáng)轉(zhuǎn)后的行為
通常的類(lèi)型強(qiáng)轉(zhuǎn)是告訴編譯器必須按照指定結(jié)構(gòu)的內(nèi)存布局來(lái)解析對(duì)應(yīng)內(nèi)存,正如上例中”Derive *pd = (Derive*)&b; “ ,編譯器就會(huì)把b對(duì)應(yīng)的內(nèi)存來(lái)當(dāng)做Derive的內(nèi)存布局來(lái)解析,但是內(nèi)存里的內(nèi)容不變,所以虛函數(shù)運(yùn)行正常。
注:這種行為很危險(xiǎn),如果使用的內(nèi)存布局并不適合真實(shí)內(nèi)存,很可能造成訪問(wèn)越界等問(wèn)題,所以要格外小心強(qiáng)轉(zhuǎn)操作的使用!對(duì)于例子中的downcasting行為,建議使用C++提供的dynamic_cast來(lái)轉(zhuǎn)換。
為了大家更好的理解上面的內(nèi)容,特附上使用指針和引用分別調(diào)用虛函數(shù)過(guò)程的gcc匯編代碼和注釋?zhuān)?br />
    Base *pb = new Derive;
  400b49:   bf 08 00 00 00          mov    $0x8,%edi
  400b4e:   e8 6d fe ff ff          callq  4009c0 <_Znwm@plt>
  400b53:   48 89 c3                mov    %rax,%rbx
  400b56:   48 89 df                mov    %rbx,%rdi
  400b59:   e8 f4 01 00 00          callq  400d52 <_ZN6DeriveC1Ev>   //以上均為Derive對(duì)象的構(gòu)造
   400b5e:   48 89 5d e8             mov    %rbx,-0x18(%rbp)             //pb指針的賦值
    pb->print();
  400b62:   48 8b 45 e8             mov    -0x18(%rbp),%rax               //pb指針指向的內(nèi)存的首地址,即Derive對(duì)象的起始地址,亦即虛表指針的地址
  400b66:   48 8b 00                mov    (%rax),%rax                        //取虛表地址
  400b69:   48 8b 00                mov    (%rax),%rax                        //取虛表中的第一項(xiàng)內(nèi)容(因Derive和Base只有一個(gè)虛函數(shù)),即print函數(shù)地址
  400b6c:   48 8b 55 e8             mov    -0x18(%rbp),%rdx               //this指針傳入rdx
  400b70:   be 0a 00 00 00          mov    $0xa,%esi                         //參數(shù)10入棧(可見(jiàn)在編譯時(shí)期就已經(jīng)確定了)
  400b75:   48 89 d7                mov    %rdx,%rdi                            //this指針借rdx傳給rdi
  400b78:   ff d0                   callq  *%rax                                     //調(diào)用虛函數(shù)(通過(guò)真實(shí)對(duì)象的虛表來(lái)確定的真正被調(diào)函數(shù))
    Base& rb = *pb;
  400b7a:   48 8b 45 e8             mov    -0x18(%rbp),%rax
  400b7e:   48 89 45 e0             mov    %rax,-0x20(%rbp)
    rb.print();
  400b82:   48 8b 45 e0             mov    -0x20(%rbp),%rax
  400b86:   48 8b 00                mov    (%rax),%rax
  400b89:   48 8b 00                mov    (%rax),%rax
  400b8c:   48 8b 55 e0             mov    -0x20(%rbp),%rdx
  400b90:   be 0a 00 00 00          mov    $0xa,%esi
  400b95:   48 89 d7                mov    %rdx,%rdi
  400b98:   ff d0                   callq  *%rax                                       //以上為通過(guò)引用調(diào)用虛函數(shù)的過(guò)程,可見(jiàn)同指針調(diào)用的實(shí)現(xiàn)完全相同,注釋略
通過(guò)上面的分析,相信大家應(yīng)該都能輕松的明白上面例子的運(yùn)行結(jié)果,此處不再一一解讀。
                                                         --by peakflys 15:57:06 Sunday, December 01, 2013

posted on 2013-12-01 16:08 peakflys 閱讀(3014) 評(píng)論(7)  編輯 收藏 引用 所屬分類(lèi): C++

評(píng)論

# re: 以題論道----關(guān)于虛函數(shù)的一些解讀 2013-12-01 19:05 Richard Wei

effective C++ item 38  回復(fù)  更多評(píng)論   

# re: 以題論道----關(guān)于虛函數(shù)的一些解讀 2013-12-02 09:32 peakflys

僅作例子講解@Richard Wei
  回復(fù)  更多評(píng)論   

# re: 以題論道----關(guān)于虛函數(shù)的一些解讀 2013-12-03 11:21 zdd

最后一個(gè)類(lèi)型轉(zhuǎn)換,這樣也可以。不知道兩者有何區(qū)別。
Derive& rd = (Derive&)b;
rd.print();  回復(fù)  更多評(píng)論   

# re: 以題論道----關(guān)于虛函數(shù)的一些解讀 2013-12-04 09:47 NWAO

".....上面例子中所有指針和引用所調(diào)用函數(shù)的參數(shù),都是指針和引用本身類(lèi)型對(duì)應(yīng)的函數(shù)默認(rèn)參數(shù),同運(yùn)行時(shí)刻他們真實(shí)指向的對(duì)象內(nèi)存無(wú)關(guān)。"

這句話(huà)加紅一下就更好了, 很重要的,同學(xué)們可以參考Effective C++ ITEM 37.  回復(fù)  更多評(píng)論   

# re: 以題論道----關(guān)于虛函數(shù)的一些解讀 2013-12-04 23:45 vsgoster

感謝,很受用~特別是默認(rèn)參數(shù)的入棧,從沒(méi)考慮過(guò)這個(gè)問(wèn)題。  回復(fù)  更多評(píng)論   

# re: 以題論道----關(guān)于虛函數(shù)的一些解讀[未登錄](méi) 2013-12-05 14:24 peakflys

@zdd 兩者沒(méi)有本質(zhì)區(qū)別。
*(Derive*)&b 先取地址,強(qiáng)轉(zhuǎn)地址類(lèi)型,然后再取內(nèi)容,同匯編實(shí)現(xiàn)基本是一一對(duì)應(yīng)起來(lái)的;
(Derive&)b是使用C式的強(qiáng)轉(zhuǎn)直接把內(nèi)容轉(zhuǎn)成Derive的引用,編譯器幫你翻譯成的匯編代碼實(shí)現(xiàn)應(yīng)該和上面的是一樣的。  回復(fù)  更多評(píng)論   

# re: 以題論道----關(guān)于虛函數(shù)的一些解讀 2013-12-12 00:00 Hacksign

博主的例子,有一個(gè)坑,具有默認(rèn)參數(shù)的virtual函數(shù)執(zhí)行靜態(tài)綁定。所以,如果去掉參數(shù),即virtual void print(void),那么第一個(gè)print調(diào)用應(yīng)該執(zhí)行derive版本的print。  回復(fù)  更多評(píng)論   

<2013年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

導(dǎo)航

統(tǒng)計(jì)

公告

人不淡定的時(shí)候,就愛(ài)表現(xiàn)出來(lái),敲代碼如此,偶爾的靈感亦如此……

常用鏈接

留言簿(4)

隨筆分類(lèi)

隨筆檔案

文章檔案

搜索

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产免费观看久久黄| 老鸭窝毛片一区二区三区 | 欧美大片免费久久精品三p| 最近看过的日韩成人| 宅男噜噜噜66国产日韩在线观看| 亚洲精品一区二区三区不| 亚洲在线观看视频| 欧美高清视频在线播放| 亚洲一区二区三区777| 久久午夜精品一区二区| 欧美色视频一区| 曰韩精品一区二区| 性欧美大战久久久久久久久| 亚洲精品1区| 日韩视频免费在线| 卡一卡二国产精品| 国产亚洲精品成人av久久ww| 久久久国产亚洲精品| 亚洲精品少妇30p| 亚洲精选视频在线| 午夜精品一区二区三区在线播放 | 久久国产免费看| 91久久精品一区| 亚洲精品色婷婷福利天堂| 亚洲精品日产精品乱码不卡| 99国产一区二区三精品乱码| 一区二区三区高清视频在线观看| 日韩天堂av| 午夜亚洲福利| 久久亚洲美女| 亚洲高清在线观看| 一区二区三区日韩在线观看| 亚洲小说春色综合另类电影| 欧美在线免费观看| 欧美二区在线播放| 国产乱人伦精品一区二区| 国内精品99| 国产精品成人一区二区三区夜夜夜 | 99精品欧美一区| 亚洲国产精品成人va在线观看| 久久不射中文字幕| 在线观看的日韩av| 欧美成人精品高清在线播放| 久久狠狠婷婷| 黄色精品一二区| 男人的天堂亚洲| 免费在线日韩av| 日韩视频专区| 国产精品99久久99久久久二8 | 久久综合婷婷| 亚洲视频一区二区在线观看 | 欧美承认网站| 欧美亚洲一区三区| 蜜臀久久99精品久久久久久9| 亚洲国产免费| 欧美在线播放高清精品| 欧美日韩91| 国模叶桐国产精品一区| 一个人看的www久久| 久久综合狠狠综合久久综青草 | 欧美日韩午夜剧场| 亚洲欧美日韩国产另类专区| 亚洲免费在线精品一区| 国产三区精品| 欧美国产激情| 国产精品夫妻自拍| 久久免费高清视频| 欧美成人一区二免费视频软件| 一区二区三区日韩在线观看| 亚洲午夜激情网页| 一区在线电影| 9l视频自拍蝌蚪9l视频成人| 国产伦精品一区二区三区照片91| 裸体歌舞表演一区二区| 欧美日韩99| 久久久人人人| 欧美日韩免费观看一区| 亚洲欧美日本国产专区一区| 久久成人精品电影| 99精品国产高清一区二区| 午夜精品久久久久久久白皮肤| 亚洲第一中文字幕| 亚洲美女视频在线观看| 国产精品自拍小视频| 亚洲国产精品va在线观看黑人| 国产精品一二| 亚洲精品日韩在线| 国产亚洲欧洲一区高清在线观看 | 亚洲一区二区视频在线观看| 亚洲国产精品第一区二区| 在线视频一区观看| 亚洲欧洲精品一区二区三区| 午夜精品电影| av成人动漫| 久久亚洲国产精品日日av夜夜| 亚洲一区欧美二区| 欧美激情 亚洲a∨综合| 久久人人爽爽爽人久久久| 欧美午夜一区二区福利视频| 欧美大片在线观看| 午夜精品999| 欧美麻豆久久久久久中文| 亚洲校园激情| 久久精品色图| 欧美影院视频| 亚洲国产激情| 日韩视频免费观看高清在线视频| 欧美午夜激情小视频| 午夜老司机精品| 久久久爽爽爽美女图片| 欧美激情1区| 亚洲成色精品| 亚洲第一精品福利| 久久蜜桃香蕉精品一区二区三区| 久久福利资源站| 国产精品一区二区久久| 亚洲一区二区视频在线| 午夜精品视频网站| 国产精品视频大全| 亚洲一区在线观看视频| 性久久久久久久久久久久| 欧美视频网站| 亚洲图中文字幕| 欧美一区视频| 国产色产综合产在线视频| 香蕉免费一区二区三区在线观看| 午夜精品www| 国产欧美日韩精品a在线观看| 亚洲欧美日韩中文视频| 久久精品夜色噜噜亚洲aⅴ| 韩日在线一区| 久久综合中文色婷婷| 欧美国产精品人人做人人爱| 亚洲精品国久久99热| 欧美精品一二三| 亚洲一区视频| 久色婷婷小香蕉久久| 在线欧美不卡| 欧美激情国产日韩精品一区18| 亚洲国产精品一区制服丝袜| 亚洲视屏在线播放| 国产视频久久| 蜜桃av噜噜一区| aaa亚洲精品一二三区| 久久国产精品久久国产精品| 伊人久久av导航| 欧美日韩精品伦理作品在线免费观看 | 欧美日韩亚洲国产精品| 一本色道**综合亚洲精品蜜桃冫| 在线视频亚洲一区| 久久久久久久久久久久久9999| 女主播福利一区| 日韩视频在线观看一区二区| 欧美风情在线| 一本到高清视频免费精品| 欧美日韩国产综合久久| 中文日韩欧美| 欧美喷潮久久久xxxxx| 久久在线观看视频| 国产美女搞久久| 在线一区二区三区四区| 亚洲大片av| 麻豆成人小视频| 久久国产精品99国产精| 欧美日韩国产成人精品| 亚洲国内高清视频| 精品99一区二区| 亚洲欧美日韩一区在线| 国产精品丝袜久久久久久app| 亚洲人成网站影音先锋播放| 亚洲第一天堂无码专区| 免费看av成人| 亚洲美女诱惑| 国产欧美精品一区二区色综合 | 一区二区三区精密机械公司| 欧美成人第一页| 欧美一区=区| 亚洲午夜高清视频| 91久久国产综合久久91精品网站| 国产精品美女久久久浪潮软件 | 99综合精品| 亚洲第一二三四五区| 国产亚洲美州欧州综合国| 欧美日韩成人在线| 中日韩视频在线观看| 欧美日韩中文精品| 欧美一区二区三区久久精品| 久久精品亚洲乱码伦伦中文| 在线播放豆国产99亚洲| 欧美日本亚洲| 欧美亚洲综合在线| 欧美激情视频一区二区三区在线播放| 亚洲国产一区二区三区青草影视 | 在线观看视频日韩| 欧美日韩视频免费播放| 久久成人免费电影| 亚洲色无码播放| 亚洲精品在线免费观看视频| 欧美在线你懂的| 亚洲永久免费观看|