深入C 的預設建構函式1

2022-08-27 15:18:09 字數 3409 閱讀 3874

總所周知,建構函式是物件重要的組成部分,承擔了物件的初始化工作。本文主要講c++下物件的預設建構函式的反彙編**,或許,這沒什麼用處,但是,知其然,還要知其所以然吧,了解底層,將對我們更好地掌握知識有很大幫助。打牢基礎,將更有利於我們的成長。「勿在浮沙築高台」-------侯捷。

當乙個物件沒有宣告建構函式的時候,編譯器會暗中為物件生成乙個預設建構函式(default constructor),被暗中生成的的預設建構函式將是乙個trivial(無用的,淺薄無能的)的函式。(摘自「深度探索c++物件模型 p40」)。下面我們來看看編譯器生成的預設建構函式。

例子1:

classa;

};int

main()

;

在vs2008下main方法的彙編**如下所示(按f5進入除錯模式,之後「alt+8」即可跳出**和彙編的混合**):

int

main()

;

下面是這段彙編**的解釋,參考:

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(){};

};

反彙編的**如下所示:

int

main()

;

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 合成的預設建構函式都做些什麼?以下三個條件同時滿足 源程式中沒有宣告任何建構函式 編譯器需要該類有預設建構函式 程式中需要呼叫預設建構函式 預設建構函式是以編譯單元為單位生成的 什麼時候編譯器需要預設建構函式 該類中有 有預設建構函式 的成員物件 該類繼承乙個有預設...