国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
潘凱:C 對(duì)象布局及多態(tài)實(shí)現(xiàn)的探索(十)

  菱形結(jié)構(gòu)的虛繼承(2)

  我們?cè)倏匆粋€(gè)例子,這個(gè)例子的繼承結(jié)構(gòu)和上一篇中是一樣的,也是菱形結(jié)構(gòu)。不同的是,每一個(gè)類都重寫了頂層類聲明的虛函數(shù)。代碼如下:
struct C041
{
    C041() : c_(0x01) {}
    virtual void foo() { c_ = 0x02; }
    char c_;
};
struct C140 : public virtual C041
{
    C140() : c_(0x02) {}
    virtual void foo() { c_ = 0x11; }
    char c_;
};
struct C141 : public virtual C041
{
    C141() : c_(0x03) {}
    virtual void foo() { c_ = 0x12; }
    char c_;
};
struct C150 : public C140, public C141
{
    C150() : c_(0x04) {}
    virtual void foo() { c_ = 0x21; }
    char c_;
};
  首先我們運(yùn)行下面的代碼,看看它們的內(nèi)存布局。
PRINT_SIZE_DETAIL(C041)
PRINT_SIZE_DETAIL(C140)
PRINT_SIZE_DETAIL(C141)
PRINT_SIZE_DETAIL(C150)
  結(jié)果為:
The size of C041 is 5
The detail of C041 is f0 c2 45 00 01
The size of C140 is 14
The detail of C140 is 48 c3 45 00 02 00 00 00 00 44 c3 45 00 01
The size of C141 is 14
The detail of C141 is 58 c3 45 00 03 00 00 00 00 54 c3 45 00 01
The size of C150 is 20
The detail of C150 is 74 c3 45 00 02 68 c3 45 00 03 04 00 00 00 00 64 c3 45 00 01
  和前面的布局不同之處在于,共享部分和前面的非共享部分之間多了4字節(jié)的0值。只有共享部分有虛表指針,這是因?yàn)榕缮惗紱]有定義自己的虛函數(shù),只是重寫了頂層類的虛函數(shù)。我們分析一下C150的對(duì)象布局。
|C140,5         |C141,5         |C150,1 |zero,4 |C041,5     |
|ospt,4,15 |m,1 |ospt,4,10 |m,1 |m,1    |4      |vtpt,4 |m1 |
  (注:為了不折行,我用了縮寫。ospt代表偏移值指針、m代表成員變量、vtpt代表虛表指針。第一個(gè)數(shù)字是該區(qū)域的大小,即字節(jié)數(shù)。只有偏移值指針有第二個(gè)數(shù)字,第二個(gè)數(shù)字就是偏移值指針指向的偏移值的大小。)
  再看函數(shù)的調(diào)用:
C150 obj;
PRINT_OBJ_ADR(obj)
obj.foo();
  輸出的對(duì)象地址為:
obj's address is : 0012F624
  最后一行函數(shù)調(diào)用的代碼對(duì)應(yīng)的匯編代碼為:
00423F74  lea         ecx,[ebp+FFFFF757h]
00423F7A  call        0041DCA3
  單步執(zhí)行后,我們可以看到ecx中的值為:0x0012F633,這個(gè)地址也就是obj對(duì)象布局中的祖父類部分的起始地址。通過上面的布局分析我們知道C150起始的偏移值指針指向的值為15,即對(duì)象起始到共享部分(祖父類部分)的偏移值。上面輸出的obj起始地址為0x0012F624加上十進(jìn)制的15后,正好是我們看到的ecx中的值0x0012f633。
  由于函數(shù)調(diào)用是作用于對(duì)象上,我們看到第二行的call指令是直接到地址的。
  在這里令人困惑的問題是,我們知道ecx是用來傳遞this指針的。在前一篇中,我們分析了在C110對(duì)象上的foo方法調(diào)用。在那個(gè)例子中,由于foo是頂層類中定義的虛函數(shù),并且沒有被下面的派生類重寫,因此通過子類對(duì)象調(diào)用這個(gè)方法時(shí),編譯器產(chǎn)生的代碼是通過子類起始的偏移指針指向的偏移值來計(jì)算出祖父類部分的起始地址,并將這個(gè)地址做為this指針?biāo)赶虻牡刂贰5窃贑150類中,foo不再是從祖父類繼承的,而是被子類自己所重寫。照理這時(shí)的this指針應(yīng)該指向子類的起始地址,也就是0x0012F62E,而不是ecx中的值0x0012F633。
  我們跟進(jìn)去看看C150::foo()的匯編代碼,看它是怎樣通過指向祖父類部分的this指針,來定位到子類的成員變量。
01 00426C00  push        ebp  
02 00426C01  mov         ebp,esp
03 00426C03  sub         esp,0CCh
04 00426C09  push        ebx  
05 00426C0A  push        esi  
06 00426C0B  push        edi  
07 00426C0C  push        ecx  
08 00426C0D  lea         edi,[ebp+FFFFFF34h]
09 00426C13  mov         ecx,33h
10 00426C18  mov         eax,0CCCCCCCCh
11 00426C1D  rep stos    dword ptr [edi]
12 00426C1F  pop         ecx  
13 00426C20  mov         dword ptr [ebp-8],ecx
14 00426C23  mov         eax,dword ptr [ebp-8]
15 00426C26  mov         byte ptr [eax-5],21h
16 00426C2A  pop         edi  
17 00426C2B  pop         esi  
18 00426C2C  pop         ebx  
19 00426C2D  mov         esp,ebp
20 00426C2F  pop         ebp  
21 00426C30  ret        
  果然,由于此時(shí)指針指向的不是子類的起始部分(而是祖父類的起始部分),因?yàn)槭峭ㄟ^減于一個(gè)偏移值為向前定位成員變量的地址的。注意第15行,這時(shí)eax中存放的是this指針的值,寫入值的地址是[eax-5],結(jié)合前面的對(duì)象布局和對(duì)象的內(nèi)存輸出,我們可以知道this指針的值(此時(shí)指向祖父類C041的起始部分)減去5個(gè)字節(jié)(4字節(jié)的0值和1字節(jié)的成員變量值)后,剛好是子類C150的起始地址。
  為什么不直接用子類的地址而是通過祖父類的起始地址間接的進(jìn)行定位?這牽涉到編譯內(nèi)部的實(shí)現(xiàn)限制和對(duì)一系統(tǒng)問題的全面的理解。只是通過分析現(xiàn)象很難找到答案。

  我們?cè)偻ㄟ^指針來調(diào)用一次。
C150 * pt = &obj;
pt->foo();
  第二行代碼對(duì)應(yīng)的匯編指令為:
01 00423F8B  mov         eax,dword ptr [ebp+FFFFF73Ch]
02 00423F91  mov         ecx,dword ptr [eax]
03 00423F93  mov         edx,dword ptr [ecx+4]
04 00423F96  mov         eax,dword ptr [ebp+FFFFF73Ch]
05 00423F9C  mov         ecx,dword ptr [eax]
06 00423F9E  mov         eax,dword ptr [ebp+FFFFF73Ch]
07 00423FA4  add         eax,dword ptr [ecx+4]
08 00423FA7  mov         ecx,dword ptr [ebp+FFFFF73Ch]
09 00423FAD  mov         edx,dword ptr [ecx+edx]
10 00423FB0  mov         esi,esp
11 00423FB2  mov         ecx,eax
12 00423FB4  call        dword ptr [edx]
13 00423FB6  cmp         esi,esp
14 00423FB8  call        0041DDF2
  喔!更加迂回了。這段代碼非常的低效,里面很多明顯的冗余指令,如第1、4、6行,2、5行等,如果打開了優(yōu)化開關(guān)可能這段指令的效率會(huì)好很多。
  第9行通過祖父類的虛表指針得到了函數(shù)地址,第11行同樣把祖父類部分的起始地址0x0012F633做為this指針指向的地址存入ecx。
  最后我們做個(gè)指針的動(dòng)態(tài)轉(zhuǎn)型再調(diào)用一次:
C141 * pt1 = dynamic_cast<C141*>(pt);
pt1->foo();
  第1行代碼對(duì)應(yīng)的匯編指令如下:
01 00423FBD  cmp         dword ptr [ebp+FFFFF73Ch],0
02 00423FC4  je          00423FD7
03 00423FC6  mov         eax,dword ptr [ebp+FFFFF73Ch]
04 00423FCC  add         eax,5
05 00423FCF  mov         dword ptr [ebp+FFFFF014h],eax
06 00423FD5  jmp         00423FE1
07 00423FD7  mov         dword ptr [ebp+FFFFF014h],0
08 00423FE1  mov         ecx,dword ptr [ebp+FFFFF014h]
09 00423FE7  mov         dword ptr [ebp+FFFFF730h],ecx
  這里實(shí)際做了一個(gè)pt是否為零的判斷,第4條指令把pt指向的地址后移了5字節(jié),最后賦給了pt1。這樣pt1就指向了右父類部分的地址位置,也就是C141的起始位置。
  第2行代碼對(duì)應(yīng)的匯編指令為:
01 00423FED  mov         eax,dword ptr [ebp+FFFFF730h]
02 00423FF3  mov         ecx,dword ptr [eax]
03 00423FF5  mov         edx,dword ptr [ecx+4]
04 00423FF8  mov         eax,dword ptr [ebp+FFFFF730h]
05 00423FFE  mov         ecx,dword ptr [eax]
06 00424000  mov         eax,dword ptr [ebp+FFFFF730h]
07 00424006  add         eax,dword ptr [ecx+4]
08 00424009  mov         ecx,dword ptr [ebp+FFFFF730h]
09 0042400F  mov         edx,dword ptr [ecx+edx]
10 00424012  mov         esi,esp
11 00424014  mov         ecx,eax
12 00424016  call        dword ptr [edx]
13 00424018  cmp         esi,esp
14 0042401A  call        0041DDF2
  由于是通過偏移值指針進(jìn)行運(yùn)算,最后在調(diào)用時(shí)ecx和edx的值和前面通過pt指針調(diào)用時(shí)是一樣的,這也是正確的多態(tài)行為。

  (未完待續(xù))

 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1777647

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
潘凱:C++對(duì)象布局及多態(tài)實(shí)現(xiàn)的探索(8-12)
通達(dá)信修改技術(shù):暴力初步(直接免費(fèi)登錄高級(jí)行情)
軟件脫殼、破重啟驗(yàn)證、追碼、制作內(nèi)存注冊(cè)機(jī)
外掛專用
qq反匯編日志
去除天狼星視頻加密系統(tǒng)的各種限制
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服