欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
潘凱:C 對象布局及多態(tài)實(shí)現的探索(八)

  普通的虛繼承

  下面我們來(lái)看虛繼承。首先看看這C020類(lèi),它從C010虛繼承:
struct C010
{
    C010() : c_(0x01) {}
    void foo() { c_ = 0x02; }
    char c_;
};
struct C020 : public virtual C010
{
    C020() : c_(0x02) {}
    char c_;
};
  運行如下代碼,查看對象的內存布局:
PRINT_SIZE_DETAIL(C020)
  結果為:
The size of C020 is 6
The detail of C020 is c0 c2 45 00 02 01
  很明顯對象的起始處是一個(gè)指針,然后是子類(lèi)的成員變量,接下來(lái)是父類(lèi)的成員變量。和以前的討論不同的是由于使用了虛繼承,父類(lèi)的成員變量被放到了最后面。
  運行如下的代碼:
C020 c020;
c020.C010::c_ = 0x04;
  由于子類(lèi)中的變量和父類(lèi)中的變量重名,所以我們必須用這種方式來(lái)訪(fǎng)問(wèn)屬于父類(lèi)的成員變量,普通情況下不需要這種寫(xiě)法。我們看看后面這行代碼對應的匯編代碼:
0042387E  mov         eax,dword ptr [ebp+FFFFF82Ch]
00423884  mov         ecx,dword ptr [eax+4]
00423887  mov         byte ptr [ebp+ecx+FFFFF82Ch],4
  前面說(shuō)過(guò)對象的起始是一個(gè)指針,第1行指令取到這個(gè)指針的值,第2行把這個(gè)指針指向的地址后移4字節后的值(做為一個(gè)4字節的值)取出來(lái)。執行完這句我們看看ecx寄存器,可知取出來(lái)的值為5。最后一行是真正的賦值指令,它通過(guò)在對象的起始處(即[ebp+FFFFF32Ch])加上ecx中的值做偏移值(即5)來(lái)得到賦值的目的地址。接合前面的對象布局輸出,我們可以發(fā)現從對象起始地址開(kāi)始加5字節的偏移值,剛好得到父類(lèi)的成員變量的地址。這樣我們可以大致分析出直接虛繼承的子類(lèi)的對象布局。
|子類(lèi)5             |父類(lèi)1   ?。?br>|偏移值指針4,5|子類(lèi)成員變量1|父類(lèi)成員變量1|
  (注:第一個(gè)數字為所在區域的長(cháng)度(字節數),偏移值指針后的第二個(gè)數字為該指針指向的偏移值。后同。)
  通過(guò)查看內存可以發(fā)現偏移值指針指向的內存前4字節為0,我不知道它的具體的用途是什么。接下來(lái)的4字節是一個(gè)32位的整數,也就是真正的偏移值。即從子類(lèi)的起始位置到被虛繼承的父類(lèi)的起始位置的偏移值,在我們前面的例子中這個(gè)值為5(一個(gè)指針加一個(gè)char成員變量)。
  通過(guò)這個(gè)分析我們可以看到在虛承繼的情況下,通過(guò)子類(lèi)的對象訪(fǎng)問(wèn)父類(lèi)的普通成員變量的效率是相當低的。如果必須用到虛繼承,也應該盡量不要在父類(lèi)中放置普通成員變量(靜態(tài)成員變量不受影響)。
  另外為什么微軟不把偏移值直接放到子類(lèi)中,而是采用偏移值指針。我想是因為采用指針的方式更為靈活,即使以后需要擴展也不影響類(lèi)對象的布局。

  按下來(lái)我們再看看這幾行代碼:
PRINT_OBJ_ADR(c020);
C010 * pt = &c020;
PRINT_PT(pt);
pt->c_ = 0x03;
  第2行聲明了一個(gè)父類(lèi)指針,并讓它指向一個(gè)子類(lèi)的對象。第3行打印出這個(gè)指針的值。運行結果為:
c020's address is : 0012F708
pt's value is : 0012F70D
  我們可以看到賦值后的指針的值并不等于賦給它的對象地址值。也就是說(shuō)在這個(gè)賦值過(guò)程中編譯器進(jìn)行了額外的工作,即調整了指針的值。我們看看第2行對應的匯編代碼,看看編譯器究竟做了些什么?
01 004238EA  lea         eax,[ebp+FFFFF82Ch]
02 004238F0  test        eax,eax
03 004238F2  jne         00423900
04 004238F4  mov         dword ptr [ebp+FFFFF014h],0
05 004238FE  jmp         00423916
06 00423900  mov         ecx,dword ptr [ebp+FFFFF82Ch]
07 00423906  mov         edx,dword ptr [ecx+4]
08 00423909  lea         eax,[ebp+edx+FFFFF82Ch]
09 00423910  mov         dword ptr [ebp+FFFFF014h],eax
10 00423916  mov         ecx,dword ptr [ebp+FFFFF014h]
11 0042391C  mov         dword ptr [ebp+FFFFF820h],ecx
  喔!比想象的要復雜的多。一行簡(jiǎn)單的指針賦值語(yǔ)句卻產(chǎn)生了這么多的匯編代碼。這行代碼本身的語(yǔ)義是取對象的地址賦給一個(gè)指針,對于編譯器來(lái)說(shuō)它把這做為指針到指針的賦值來(lái)處理。由于牽涉到了向上的類(lèi)型轉換,同時(shí)又有虛繼承存在。根據前面的布局分析,在虛繼承的情況下,父類(lèi)位于對象布局的后部。因此在這里要做一個(gè)指針位置的調整。由于調整要根據源指針來(lái)進(jìn)行計算,所以先要對源指針的合法性進(jìn)行檢查,以避免運行時(shí)的指針異常錯誤。前3行的匯編指令就是在做這件事,檢查源指針是否為NULL。如果為NULL則執行4、5、10、11行,最終給pt賦0。如果不為NULL跳至第6行執行到最后。重要的是第6、7、8行代碼,它們通過(guò)偏移值指針找到偏移值,并以此來(lái)調整指針的位置,讓目的指針最終指向對象中的父類(lèi)部分的數據成員。
  對比一下普通的指針賦值,我們可以對上面賦值的復雜性和低效有更深的認識。
C010 * pt1 = NULL;
C010 * pt2 = pt1;
  這兩行相應的匯編代碼為:
0042397D  mov         dword ptr [ebp+FFFFF814h],0
00423987  mov         eax,dword ptr [ebp+FFFFF814h]
0042398D  mov         dword ptr [ebp+FFFFF808h],eax
  第1行是普通的賦值,編譯器并不做任何的檢查,即使源指針為NULL。因為它不需要根據源指針(本處為NULL)做任何計算。第2個(gè)賦值也很直接,只是通過(guò)eax做了一個(gè)中轉。這里我們就可以看到前面的虛繼承下的子類(lèi)指針到父類(lèi)指針的賦值是我么的低效。在程序中應盡量的避免這種代碼。

  (未完待繼)

 
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
潘凱:C++對象布局及多態(tài)實(shí)現的探索(8-12)
c++虛函數機制
C++對象布局及多態(tài)之虛成員函數如何調用 -- RocketMan'sRoom -- 編程...
淺析C++中的this指針 - 數組指針 - 龍行天下
常量、指針和變量的實(shí)現機制
你想錯了,并不是所有指針都是4字節。
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久