總所周知,建構函式是物件重要的組成部分,承擔了物件的初始化工作。本文主要講c++下物件的預設建構函式的反彙編**,或許,這沒什麼用處,但是,知其然,還要知其所以然吧,了解底層,將對我們更好地掌握知識有很大幫助。打牢基礎,將更有利於我們的成長。「勿在浮沙築高台」-------侯捷。當乙個物件沒有宣告建構函式的時候,編譯器會暗中為物件生成乙個預設建構函式(default constructor),被暗中生成的的預設建構函式將是乙個trivial(無用的,淺薄無能的)的函式。(摘自「深度探索c++物件模型 p40」)。下面我們來看看編譯器生成的預設建構函式。
例子1:
classa;};int
main()
;
在vs2008下main方法的彙編**如下所示(按f5進入除錯模式,之後「alt+8」即可跳出**和彙編的混合**):
intmain()
;
下面是這段彙編**的解釋,參考:
push ebp;將ebp壓入棧,ebp主要用來儲存當前棧幀的棧底指標,所有的區域性變數都是用相對於ebp的偏移來使用的。
move ebp,esp
sub esp,occh;
這兩句的意思是是將當前棧頂作為這一棧幀的基值。並且為本函式分配了0cch*4個位元組的棧空間。因為棧頂往上走了cc步。
push
ebxpush
esipush edi;
這三句的意思是將上個函式所使用的暫存器的值壓入棧中,即儲存上個方法所使用的暫存器值,為了執行完本函式後能返回去。
leaedi, [ebp-0cch]
movecx,33h
moveax,0cccccccch
rep stos dword ptr es:[edi];
上面4句**的意思是將ebp到0cch的棧空間(33h * 4位元組)通過rep(迴圈指令)置為0cch。
通過上面的彙編,我們可以知道對於乙個這樣簡單的類(只宣告了乙個方法的類),編譯器生成的**甚至沒有呼叫它的建構函式(應該編譯器沒有暗中合成它的建構函式)。
例子2:
當我們將a的宣告改為:
classa;void
print(){};
};
反彙編的**如下所示:
intmain()
;
a的建構函式反彙編如下:
a(){};00b61440
push
ebp
00b61441
movebp,esp
00b61443
subesp,0cch
00b61449
push
ebx
00b6144a
push
esi
00b6144b
push
edi
00b6144c
push
ecx
00b6144d
leaedi,[ebp-0cch]
00b61453
movecx,33h
00b61458
moveax,0cccccccch
00b6145d
rep stos dword ptr es:
[edi]
00b6145f
popecx
00b61460
mov dword ptr [ebp-8
],ecx
00b61463
moveax,dword ptr [this]
00b61466
popedi
00b61467
popesi
00b61468
popebx
00b61469
movesp,ebp
00b6146b
popebp
00b6146c
ret
對照前面的解釋,a::a()是啥事都沒做(在將申請的棧空間置為0後就開始將退出函式),這段彙編**或許說明我們宣告個空建構函式是件沒意義的事(當然,帶有成員初始化列表的空建構函式不算)。
例子3:
下面再給類的定義添些東西:
classa;void
print(){};
private
:int
m_nvalue;
};
直接貼它的建構函式:
a(){};00e21420
push
ebp
00e21421
movebp,esp
00e21423
subesp,0cch
00e21429
push
ebx
00e2142a
push
esi
00e2142b
push
edi
00e2142c
push
ecx
00e2142d
leaedi,[ebp-0cch]
00e21433
movecx,33h
00e21438
moveax,0cccccccch
00e2143d
rep stos dword ptr es:
[edi]
00e2143f
popecx
00e21440
mov dword ptr [ebp-8
],ecx
00e21443
moveax,dword ptr [this]
00e21446
popedi
00e21447
popesi
00e21448
popebx
00e21449
movesp,ebp
00e2144b
popebp
00e2144c
ret
和例子2的建構函式對比,**完全一樣,這說明類中的成員變數在初始化的時候需要是乙個特定值的話,應該自己手動初始化,編譯器是不會負責這個事情的。但是,當我們類中有成員變數的時候,類構造的時候最好將成員變數初始化相應的初值,這是個良好的程式設計習慣,這次就先說到這裡了,複雜的預設建構函式(成員變數有default建構函式的預設建構函式,繼承下的建構函式,有虛函式的建構函式)的反彙編會在下面的系列繼續。
這是我第一次寫部落格,請大家多多指導,謝謝大家。
深入探索預設建構函式
問題 傳統認識為 如果我們自己在類中沒有定義任何建構函式,那麼編譯器就會為我們隱式自動生成乙個預設的建構函式,我們稱這種建構函式為 合成的預設建構函式 事實的真相果真如此嗎?結論 合成預設建構函式 只有在必要的時候,編譯器才會為我們自動合成出來,而不是必然為我們合成出來。那到底什麼時候是必要的呢?演...
C 預設建構函式
c 預設建構函式 一直認為若程式設計師沒有自己定義無引數的建構函式,那麼編譯器會自動生成預設建構函式,來進行對成員函式的初始化,但這種認為是有誤的,不全面的.預設的建構函式分為有用的和無用的,所謂無用的預設建構函式就是乙個空函式 什麼操作也不做,而有用的預設建構函式是可以初始化成員的函式。對建構函式...
c 預設建構函式
c 什麼時候合成預設建構函式?c 合成的預設建構函式都做些什麼?以下三個條件同時滿足 源程式中沒有宣告任何建構函式 編譯器需要該類有預設建構函式 程式中需要呼叫預設建構函式 預設建構函式是以編譯單元為單位生成的 什麼時候編譯器需要預設建構函式 該類中有 有預設建構函式 的成員物件 該類繼承乙個有預設...