详解虚函数的实现过程之菱形继承(5)
大家看到標題,會不會菱形繼承的虛表會不會是重復的呢?祖父類的虛表會不會在子類會不會是兩份相同呢?那么我們一起來探索一下吧,沖沖沖!!
首先我們來分析一下:
它一共定義了四個類,分別為CFurniture,CSofa,CBed和CSofaBed。CFurniture為祖父類,從CFurniture類中派生了兩個子類:CSofa與CBed,它們在繼承時使用了virtual的方式,即虛繼承。
接下來我們來看看CSofaBed的對象的內存結構圖
那么這些數據都有什么含義呢?如下所示:
看了一下,大概能看懂,但是還有一個模糊不清的數據無法理解,就像CSofaBed_vt(new)和vt_offset,他們又代表什么東西呢?唉,只能去探索匯編代碼,繼續沖沖沖!!!
在這里解釋一下地址40F732~40F742之間匯編代碼的作用:
ebp-24h是對象的向后偏移四個字節的地址,因為ebp-28h是this指針,也就是對象的首地址,this值即內存圖中的12FF58,所以[ebp-24h]也就是對象的第二個字節的數據,其實說白了它還是個地址,也就是12-13內存圖中的第二行數據 425050,即[ebp-24h]的值是425050,然后放入ecx中,ecx+4也就是這個地址向后偏移 4個字節,即425054,然后[ecx+4]的值即為1C,這個值就是父類虛表指針相對于vt_offset的偏移,然后把這個值放入edx,作為一個偏移值,ebp-24h+edx 意思就是相對于第二個字節的偏移為1C的地址,[ebp-24h+edx]不就是這個地址的值了嗎?也就是祖父類的首地址,即祖父類的虛表指針的地址
上面分析了一下匯編代碼,分析出了vt_offset所指向的內存地址中保存的數據為偏移數據。如下圖,圖中每個vt_offset對應的數據有兩項:第一項是-4,即vt_offset所屬類對應的虛表指針相對于vt_offset的偏移值;第二項保存的是父類虛表指針相對于vt_offset的偏移值(上面已分析結束,至于第一項的話,大家看匯編代碼都能看出)
根據上面我們找出的vt_offset是地址12FF5C,向下偏移1C的話,1C是多少個字節?剛開始我一直搞成12個字節?!!!!!我都搞不懂那個1被我想哪去了?!!!1C也就是 16+12=28個字節,也就是向下偏移7行,即到地址12FF78處,它的值為42501C,這也就是父類虛指針的地址。當然也可以用第二個來算,因為它倆的父類都是同一個,所以算出來的地址肯定也是42501C(快速算一下:也就是425044的地址是12FF68,然后向下偏移10h(16個字節)個字節,也就是4行,即12FF78處,值為42501C)
根據前面所述,這里有三個虛表指針:
0x425034(用0x12FF5C -0x4=0x12FF58,根據上面內存圖此處地址的值為0x425034),0x425028(從匯編代碼地址0x40F752分析得出)(至于0x12FF68如何得來,需要去分析匯編代碼,用0x12FF68 -0x4=0x12FF64,根據上面內存圖此處地址的值為0x425028),
0x42501C(已算出是祖父類起始地址)
所以總結如下:
vt_offset是一個地址,這個地址所指向的地方存在了兩個偏移值,第一個值是當前類對應的虛表指針相對于vt_offset的偏移值,第二個值是父類對應的虛表指針相對于vt_offset的偏移值,每個虛繼承類都有一個相應的vt_offset,可找到父類的虛表指針,也可找到自身類的虛表指針。
這三個虛表指針指向的虛表包含了子類CSofaBed含有的虛函數有了這些記錄就可以隨心所欲地將虛表指針轉換成任意的父類指針。
在利用父類指針父類指針訪問虛函數時,只能調用子類與父類共有的虛函數,子類繼承自其它父類的虛函數是無法調用的,虛表中也沒有相關記錄。當子類的父類存在多個父類時,會在12-15所顯示的表格中依次記錄它們的偏移。
虛函數系列:
詳解虛函數的實現過程之初探虛表(1)
詳解虛函數的實現過程之單繼承(2)
詳解虛函數的實現過程之多重繼承(3)
詳解虛函數的實現過程之虛基類(4)
詳解虛函數的實現過程之菱形繼承(5)
總結
以上是生活随笔為你收集整理的详解虚函数的实现过程之菱形继承(5)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 详解虚函数的实现过程之虚基类(4)
- 下一篇: 静态反调试技术(1)