首先從帶有虛函式的基類派生講起。
class base
virtual ~base()
virtual void say()
int base;
};class derive : public base
virtual ~derive()
virtual void say()
int derive;
};int _tmain(int argc, _tchar* ar**)
這是乙個很簡單的派生的例子,首先從記憶體角度看下,期中0x003b94b0為指標pd的值
可以看到最開始的四個位元組的值為0x00417700, 後面是兩個int型值分別為1和2,代表著base和derive的值,這兩個值是在建構函式裡進行賦值的,現在主要看下0x00417700這個值代表著什麼?
0x00417700這個記憶體位置的值是0x004112c6,在繼續跟下0x004112c6這個記憶體位置有什麼東西
004112c6 jmp derive::`scalar deleting destructor' (414980h)
可以看到這個地方是跳到乙個好像是derive的析構函式處,其實進去之後會發現其實他是乙個**函式,在此函式中先呼叫derive的析構函式,然後在呼叫operator delete 釋放記憶體。可以通過反彙編**來看下:
derive::`scalar deleting destructor':
00414980 push ebp
。。。。
0041499f pop ecx
004149a0 mov dword ptr [ebp-8],ecx
004149a3 mov ecx,dword ptr [this]
004149a6 call derive::~derive (4112b2h)
004149ab mov eax,dword ptr [ebp+8]
004149ae and eax,1
004149b1 je derive::`scalar deleting destructor'+3fh (4149bfh)
004149b3 mov eax,dword ptr [this]
004149b6 push eax
004149b7 call operator delete (4110d2h)
中間的省略掉了,無關緊要,主要是將開闢的一段棧空間的內容初始化為0xcccccccc,在紅色處可以看到derive的析構函式的呼叫。現在在回到開頭處,用一張圖示意下
可以看到derive型別的物件的記憶體布局,首先是乙個虛表指標,然後是基類的成員變數最後才是自己的成員變數
現在來**下這個指向虛表的指標式什麼時候安插到物件的頭部的,我們通過派生類的建構函式來看下:
derive()
004116a0 push ebp
。。。。。。
004116bf pop ecx
004116c0 mov dword ptr [ebp-8],ecx //ecx為this的值
004116c3 mov ecx,dword ptr [this]
004116c6 call base::base (41115eh)
004116cb mov eax,dword ptr [this]
004116ce mov dword ptr [eax],offset derive::`vftable' (417700h)
通過**建構函式的反彙編**可以看到,在派生類的建構函式中先是呼叫基類base的建構函式,現在我們跟到基類的建構函式中去:
base():
004117b0 push ebp
。。。。。
004117cf pop ecx
004117d0 mov dword ptr [ebp-8],ecx
004117d3 mov eax,dword ptr [this]
004117d6 mov dword ptr [eax],offset base::`vftable' (417718h)
004117dc mov eax,dword ptr [this]
004117df mov dword ptr [eax+4],1
004117e6 push offset string "base!\n" (417708h)
004117eb mov eax,dword ptr [__imp_std::cout (41b328h)]
004117f0 push eax
004117f1 call std::operator<<> (4111a4h)
通過基類的建構函式可以看到,他將offset base::`vftable' (417718h)基類的虛表位址賦給了物件的頭四個位元組,然後才是執行基類建構函式中的**,現在我們可以看到pd頭部的四個位元組的值不是417700h而是417718h,奇怪了別急,後面會看到417700h這個值是賦給pd頭部的四個位元組。基類的建構函式執行完畢之後回到派生類的建構函式,此事可以看到緊接著就是兩個賦值語句
004116cb mov eax,dword ptr [this]
004116ce mov dword ptr [eax],offset derive::`vftable' (417700h)
首先是將this指標的值賦給eax,然後將offset derive::`vftable' (417700h)派生類的虛表的指標賦給eax所指向的位址的頭四個位元組,也就是賦給pd所指的派生類物件的頭四個位元組,現在到此也就分析完了其記憶體布局,以及虛表指標的賦值過程。
Volatile底層原理剖析
基礎知識回顧 還是那句話,無論語言再怎麼牛,其都是對底層計算機指令的封裝。計算機cpu執行指令的時候是非常快的,如果每執行乙個指令都從記憶體中取資料的話,那會非常慢,嚴重影響cpu的執行速度,所以每個cpu都有自身對應的高速緩衝區 多級暫存器 每個執行緒被執行的時候,會先把執行時需要的資料複製到告訴...
HashMap底層原理簡單剖析
1 hashmap的儲存結構 陣列 鍊錶 紅黑樹 jdk1.8 如下圖所示 2 hashmap的特點,如何實現 我們知道hashmap是一種可以快速儲存很快速查詢的鍵值容器,那麼jdk是如何實現hashmap的快速儲存和快速查詢呢?我們先從陣列和鍊錶以及二叉查詢樹這三種資料結構說起 1 陣列 陣列結...
深度剖析Spring Cloud底層原理
毫無疑問,spring cloud 是目前微服務架構領域的翹楚,無數的書籍部落格都在講解這個技術。不過大多數講解還停留在對 spring cloud 功能使用的層面,其底層的很多原理,很多人可能並不知曉。實際上,spring cloud 是乙個全家桶式的技術棧,它包含了很多元件。本文先從最核心的幾個...