成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

C++中虛函數(shù)的調(diào)用及對(duì)象的內(nèi)部布局是什么樣的-創(chuàng)新互聯(lián)

C++中虛函數(shù)的調(diào)用及對(duì)象的內(nèi)部布局是什么樣的,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。

創(chuàng)新互聯(lián)專注于唐山企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站開(kāi)發(fā),成都做商城網(wǎng)站。唐山網(wǎng)站建設(shè)公司,為唐山等地區(qū)提供建站服務(wù)。全流程按需網(wǎng)站策劃,專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)

這次我依然用分析C++代碼編譯后生成的匯編代碼來(lái)說(shuō)明C++中虛函數(shù)調(diào)用的實(shí)現(xiàn)方法,順便也說(shuō)明一下C++中的對(duì)象內(nèi)部布局。下面所有的匯編代碼都是用VC2005編譯出來(lái)的。雖然,不同的編譯器可能會(huì)編譯出不同的結(jié)果,對(duì)象的內(nèi)部布局也不盡相同;但是,只要是符合C++標(biāo)準(zhǔn)的編譯器,編譯結(jié)果和對(duì)象的內(nèi)部布局應(yīng)該是大同小異。


    首先,是一個(gè)有著簡(jiǎn)單繼承關(guān)系的兩個(gè)類: class CBase
{
public:
    virtual void VFun1() = 0;
    virtual void VFun2() = 0;
    void Fun1();
};

// 這里僅僅是為了生成函數(shù)的匯編代碼,因此函數(shù)體為空
void CBase::Fun1()
{
}

class CDerived : public CBase
{
public:
    virtual void VFun1();
    virtual void VFun2();
    void Fun2();
private:
    int m_iValue1;
    int m_iValue2;
};

// 這里僅僅是為了生成函數(shù)的匯編代碼,因此函數(shù)體為空
void CDerived::VFun1()
{
}

// 這里僅僅是為了生成函數(shù)的匯編代碼,因此函數(shù)體為空
void CDerived::VFun2()
{
}

// 這里是為了分析對(duì)象的內(nèi)部布局,因此僅僅是給成員變量賦值
void CDerived::Fun2()
{
    m_iValue1 = 13;
    m_iValue2 = 13;
}
    現(xiàn)在用下面的代碼來(lái)調(diào)用成員函數(shù):

CDerived derived;

// 用對(duì)象調(diào)用虛函數(shù)
derived.VFun1();
derived.VFun2();
// 用對(duì)象調(diào)用非虛函數(shù)
derived.Fun1();
derived.Fun2();

// 用指向派生類的基類的指針調(diào)用虛函數(shù),實(shí)現(xiàn)多態(tài)
CBase *pTest = &derived;
pTest->VFun1();
pTest->VFun2();
    下面就是用VC2005編譯上面的代碼后生成的匯編代碼:

    CDerived derived;
0041195E  lea         ecx,[derived]
00411961  call        CDerived::CDerived (411177h)

// 代碼段1
    derived.VFun1();
00411966  lea         ecx,[derived]
00411969  call        CDerived::VFun1 (411078h)
    derived.VFun2();
0041196E  lea         ecx,[derived]
00411971  call        CDerived::VFun2 (4111B8h)
    derived.Fun1();
00411976  lea         ecx,[derived]
00411979  call        CBase::Fun1 (411249h)
    derived.Fun2();
0041197E  lea         ecx,[derived]
00411981  call        CDerived::Fun2 (4111BDh)

// 代碼段2
    CBase *pTest = &derived;
00411986  lea         eax,[derived]
00411989  mov         dword ptr [pTest],eax
    pTest->VFun1();
0041198C  mov         eax,dword ptr [pTest] // 行1
0041198F  mov         edx,dword ptr [eax] // 行2
00411991  mov         esi,esp
00411993  mov         ecx,dword ptr [pTest]
00411996  mov         eax,dword ptr [edx] // 行3
00411998  call        eax // 行4 
0041199A  cmp         esi,esp
0041199C  call        @ILT+495(__RTC_CheckEsp) (4111F4h)
    pTest->VFun2();
004119A1  mov         eax,dword ptr [pTest]
004119A4  mov         edx,dword ptr [eax]
004119A6  mov         esi,esp
004119A8  mov         ecx,dword ptr [pTest]
004119AB  mov         eax,dword ptr [edx+4] // 行5
004119AE  call        eax 
004119B0  cmp         esi,esp
004119B2  call        @ILT+495(__RTC_CheckEsp) (4111F4h)
    通過(guò)對(duì)代碼段1的觀察我們可以發(fā)現(xiàn):通過(guò)對(duì)象調(diào)用類的虛成員函數(shù)和調(diào)用非虛成員函數(shù)是相同的(對(duì)調(diào)用成員函數(shù)的匯編代碼的分析可以看我的那篇《淺析C++中的this指針》)。也就是說(shuō),用對(duì)象是無(wú)法實(shí)現(xiàn)多態(tài)的。
    下面主要來(lái)分析實(shí)現(xiàn)多態(tài)的代碼段2。
    行1、將pTest指針指向的地址前2個(gè)字(4個(gè)字節(jié),也就是32位系統(tǒng)中一個(gè)指針的大小)的內(nèi)容當(dāng)成一個(gè)指針?lè)诺絜ax寄存器中
    行2、將eax寄存器中的指針的值放入edx寄存器
    行3、將dex寄存器中的指針的值放入eax寄存器
    行4、調(diào)用eax寄存器指向的函數(shù)
    這樣分析似乎對(duì)怎樣調(diào)用對(duì)象derived的虛函數(shù)VFun1()并不是很清楚。那么我們先來(lái)看下面的這張圖:

    這張圖是一個(gè)假設(shè)的對(duì)象derived在內(nèi)存中的內(nèi)部布局圖。指針pTest指向?qū)ο骴erived,而對(duì)象derived的前4個(gè)字節(jié)是一個(gè)虛表指針,指向虛函數(shù)表。
    看著這張圖再來(lái)分析上面的匯編代碼就會(huì)清晰很多:
    行1、取得虛表指針值放入eax寄存器中
    行2、取得虛表指針的值放入edx寄存器中
    行3、取得虛表指針指向的地址的值(也就是VFun1)放入eax寄存器中
    行4、調(diào)用eax寄存器指向的函數(shù)
    行5證明了上面圖中對(duì)虛函數(shù)表的假設(shè)。第二個(gè)虛函數(shù)VFun2()的地址就是通過(guò)在第一虛函數(shù)VFun1()的地址加4(32位系統(tǒng)中一個(gè)指針的大小)而得到的。
    通過(guò)上面的分析,可以得出C++中虛函數(shù)的調(diào)用方法:首先,取得對(duì)象中的虛表指針;然后,通過(guò)虛表指針找到相應(yīng)的虛表;最后,通過(guò)在虛表內(nèi)的偏移量找到相應(yīng)的函數(shù)來(lái)調(diào)用。
    下面通過(guò)分析類CDerived的非虛成員函數(shù)Fun2()來(lái)證明上面圖中虛函數(shù)表指針的存在。

void CDerived::Fun2()
{
004118F0  push        ebp 
004118F1  mov         ebp,esp
004118F3  sub         esp,0CCh
004118F9  push        ebx 
004118FA  push        esi 
004118FB  push        edi 
004118FC  push        ecx 
004118FD  lea         edi,[ebp-0CCh]
00411903  mov         ecx,33h
00411908  mov         eax,0CCCCCCCCh
0041190D  rep stos    dword ptr es:[edi]
0041190F  pop         ecx 
00411910  mov         dword ptr [ebp-8],ecx
    m_iValue1 = 13;
00411913  mov         eax,dword ptr [this] // 行6
00411916  mov         dword ptr [eax+4],0Dh // 行7
    m_iValue2 = 13;
0041191D  mov         eax,dword ptr [this]
00411920  mov         dword ptr [eax+8],0Dh
}
00411927  pop         edi 
00411928  pop         esi 
00411929  pop         ebx 
0041192A  mov         esp,ebp
0041192C  pop         ebp 
0041192D  ret 
    上面是類CDerived的非虛成員函數(shù)Fun2()的匯編代碼??梢钥吹?,行6是將this指向的地址放入eax寄存器,而行7是給this指針指向的地址加4的地址賦值(具體的分析,可以看《淺析C++中的this指針》),而這個(gè)地址里面存放的是類CDerived的第一個(gè)成員變量。我們知道this指針是指向?qū)ο笫椎刂返模敲礊槭裁匆o第一個(gè)成員變量賦值的時(shí)候要向后移動(dòng)4個(gè)字節(jié)?答案是因?yàn)閷?duì)象的前4個(gè)字節(jié)是用來(lái)存放虛表指針的。
    下面的代碼是《淺析C++中的this指針》一文中的不含虛函數(shù)的類的C++代碼和編譯后的匯編代碼:

class CTest
{
public:
    void SetValue();

private:
    int m_iValue1;
    int m_iValue2;
};

void CTest::SetValue()
{
    m_iValue1 = 13;
    m_iValue2 = 13;
}

void CTest::SetValue()
{
004117E0  push        ebp 
004117E1  mov         ebp,esp
004117E3  sub         esp,0CCh
004117E9  push        ebx 
004117EA  push        esi 
004117EB  push        edi 
004117EC  push        ecx 
004117ED  lea         edi,[ebp-0CCh]
004117F3  mov         ecx,33h
004117F8  mov         eax,0CCCCCCCCh
004117FD  rep stos    dword ptr es:[edi]
004117FF  pop         ecx 
00411800  mov         dword ptr [ebp-8],ecx
    m_iValue1 = 13;
00411803  mov         eax,dword ptr [this] // 行8
00411806  mov         dword ptr [eax],0Dh // 行9
    m_iValue2 = 13;
0041180C  mov         eax,dword ptr [this]
0041180F  mov         dword ptr [eax+4],0Dh
}
00411816  pop         edi 
00411817  pop         esi 
00411818  pop         ebx 
00411819  mov         esp,ebp
0041181B  pop         ebp 
0041181C  ret 
    通過(guò)行8、行9和行6、行7的比較就可以看出:類CTest的對(duì)象前4個(gè)字節(jié)存放的是自己的第一個(gè)成員變量;而類CDerived的對(duì)象從第5個(gè)字節(jié)開(kāi)始才是存放的自己的第一個(gè)成員變量,它的前4個(gè)字節(jié)是用來(lái)存放虛表指針的。這再一次證明了上面圖中對(duì)象內(nèi)部布局的正確

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司,的支持。

分享標(biāo)題:C++中虛函數(shù)的調(diào)用及對(duì)象的內(nèi)部布局是什么樣的-創(chuàng)新互聯(lián)
分享地址:http://jinyejixie.com/article12/jgodc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站策劃域名注冊(cè)、服務(wù)器托管、標(biāo)簽優(yōu)化、網(wǎng)站導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)
孝义市| 阿克陶县| 师宗县| 乡城县| 多伦县| 巴林右旗| 平舆县| 恩平市| 英吉沙县| 德州市| 山丹县| 海门市| 苍梧县| 临高县| 都匀市| 磴口县| 昌吉市| 九龙坡区| 呈贡县| 沂水县| 苏尼特右旗| 普安县| 普安县| 洪雅县| 徐州市| 镇远县| 吉安市| 石屏县| 萝北县| 定结县| 余姚市| 曲水县| 临漳县| 通山县| 揭西县| 瑞丽市| 嘉峪关市| 龙海市| 郁南县| 萨迦县| 罗定市|