小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

C++類對(duì)象創(chuàng)建過程揭密

 曾經(jīng)艱難走過 2010-04-03

 

介紹
初 看到這個(gè)題目,你可能會(huì)有些疑惑:C++類對(duì)象的創(chuàng)建還有什么好說的,不就是調(diào)用構(gòu)造函數(shù)么?實(shí)際上情況并不是想象中的那么簡(jiǎn)單,大量的細(xì)節(jié)被隱藏或者被 忽略了,而這些細(xì)節(jié)又是解決一些其他問題的關(guān)鍵,所以我們很有必要深入到這塊"神秘"的區(qū)域,去探索鮮為人知的秘密。

分配空間(Allocation)
創(chuàng)建C++類對(duì)象的第一步就是為其分配內(nèi)存空間。對(duì)于全局對(duì)象,靜態(tài)對(duì)象以及分配在棧區(qū)域內(nèi)的對(duì)象,對(duì)它們的內(nèi)存分配是在編譯階段就完成了,而對(duì)于分配在堆區(qū)域內(nèi)的對(duì)象,它們的分配是在運(yùn)行是動(dòng)態(tài)進(jìn)行的。內(nèi)存空間的分配過程涉及到兩個(gè)關(guān)鍵的問題:

需要分配空間的大小,即類對(duì)象的大小。這么問題對(duì)于編譯器來說并不是什么問題,因?yàn)轭悓?duì)象的大小就是由它決定的,對(duì)于要分配多少內(nèi)存,它最清楚不過了。
是否有足夠的內(nèi)存空間來滿足分配。對(duì)于不同的情況我們需要具體問題具體分析:
全局對(duì)象和靜態(tài)對(duì)象。編譯器會(huì)為他們劃分一個(gè)獨(dú)立的段(全局段)為他們分配足夠的空間,一般不會(huì)涉及到內(nèi)存空間不夠的問題。
分配在棧區(qū)域的對(duì)象。棧區(qū)域的大小由編譯器的設(shè)置決定,不管具體的設(shè)置怎樣,總歸它是有一個(gè)具體的值,所以??臻g是有限的,在棧區(qū)域內(nèi)同時(shí)分配大量的對(duì)象會(huì)導(dǎo)致棧區(qū)域溢出,由于棧區(qū)域的分配是在編譯階段完成的,所以在棧區(qū)域溢出的時(shí)候會(huì)拋出編譯階段的異常。
分配在堆區(qū)域的對(duì)象。堆內(nèi)存空間的分配是在運(yùn)行是進(jìn)行的,由于堆空間也是有限的,在棧區(qū)域內(nèi)試圖同時(shí)分配大量的對(duì)象會(huì)導(dǎo)致導(dǎo)致分配失敗,通常情況會(huì)拋出運(yùn)行時(shí)異?;蛘叻祷匾粋€(gè)沒有意義的值(通常是0)。
初始化(Initialization)
這 一階段是對(duì)象創(chuàng)建過程中最神秘的一個(gè)階段,也是最容易被忽視的一個(gè)階段。要想知道這一階段具體完成那些任務(wù),關(guān)鍵是要區(qū)分兩個(gè)容易混淆的概念:初始化 (Initialization)和賦值(Assignment)。初始化早于賦值,它是隨著對(duì)象的誕生一起進(jìn)行的。而賦值是在對(duì)象誕生以后又給予它一個(gè) 新的值。這里我想到了一個(gè)很好的例子:任何一個(gè)在醫(yī)院誕生的嬰兒,在它誕生的同時(shí)醫(yī)院會(huì)給它一個(gè)標(biāo)識(shí),以防止和其他的嬰兒混淆,這個(gè)標(biāo)識(shí)通常是嬰兒母親所 在床鋪的編號(hào),醫(yī)院給嬰兒一個(gè)標(biāo)識(shí)的過程可以看作是初始化。當(dāng)然當(dāng)嬰兒的父母拿到他們會(huì)為他們起個(gè)名字,起名字的過程就可以看作是賦值。經(jīng)過初始化和賦值 后,其他人就可以通過名字來標(biāo)識(shí)他們的身份了。區(qū)分了這兩個(gè)概念后,我們?cè)俎D(zhuǎn)到對(duì)對(duì)象初始化的分析上。對(duì)類對(duì)象的初始化,實(shí)際上是對(duì)類對(duì)象內(nèi)的所有數(shù)據(jù)成 員進(jìn)行初始化。C++已經(jīng)為我們提供了對(duì)類對(duì)象進(jìn)行初始化的能力,我們可以通過實(shí)現(xiàn)構(gòu)造函數(shù)的初始化列表(member initialization list)來實(shí)現(xiàn)。具體的情況是否是這樣的呢?下面我們就看看具體的情況是什么樣的吧。我寫了兩個(gè)簡(jiǎn)單的類:     class CInnerClass {
    public:
        CInnerClass(int id):m_iID(id) {}
        CInnerClass& operator = (const CInnerClass& rb) {
            m_iID = rb.m_iID;
            return *this;
        }
    private:
        int m_iID;
    };
   
    class CJdBase {
    public:
        CJdBase::CJdBase(int id):m_innerObj(id),m_iID(id){
            m_innerObj = 10;
        }
    private:
        CInnerClass m_innerObj;
        int m_iID;
    };我們重點(diǎn)是看看CJdBase類的構(gòu)造函數(shù)。CJdBase類的構(gòu)造函數(shù)提供了初始化列表,用來初始化其成員變量,其相應(yīng)的匯編代碼如下(注:我只保留了關(guān)鍵的代碼):     mov    DWORD PTR _this$[ebp], ecx
    mov    eax, DWORD PTR _id$[ebp]
    push    eax
    mov    ecx, DWORD PTR _this$[ebp]
    call    ??0CInnerClass@@QAE@H@Z            ; CInnerClass::CInnerClass
    mov    eax, DWORD PTR _this$[ebp]
    mov    ecx, DWORD PTR _id$[ebp]
    mov    DWORD PTR [eax+4], ecx

; 5    :     m_innerObj = 10;

    push    10                    ; 0000000aH
    lea    ecx, DWORD PTR $T1359[ebp]
    call    ??0CInnerClass@@QAE@H@Z            ; CInnerClass::CInnerClass
    lea    eax, DWORD PTR $T1359[ebp]
    push    eax
    mov    ecx, DWORD PTR _this$[ebp]
    call    ??4CInnerClass@@QAEAAV0@ABV0@@Z        ; CInnerClass::operator=從這段匯編代碼中我們可以看到一些有意義的內(nèi)容:

初始化列表先于構(gòu)造函數(shù)體內(nèi)的代碼執(zhí)行;
初始化列表確實(shí)執(zhí)行的是數(shù)據(jù)成員的初始化過程,這個(gè)可以從成員對(duì)象的構(gòu)造函數(shù)被調(diào)用看的出來。
賦值(Assignment)
對(duì) 象經(jīng)過初始化以后,我們?nèi)匀豢梢詫?duì)其進(jìn)行賦值。和類對(duì)象的初始化一樣,類對(duì)象的賦值實(shí)際上是對(duì)類對(duì)象內(nèi)的所有數(shù)據(jù)成員進(jìn)行賦值。C++也已經(jīng)為我們提供了 這樣的能力,我們可以通過構(gòu)造函數(shù)的實(shí)現(xiàn)體(即構(gòu)造函數(shù)中由"{}"包裹的部分)來實(shí)現(xiàn)。這一點(diǎn)也可以從上面的匯編代碼中成員對(duì)象的賦值操作符 (operator =)被調(diào)用得到印證。

結(jié)束
隨著構(gòu)造函數(shù)執(zhí)行完最后一行代碼,可以說類對(duì)象的創(chuàng)建過程也就順利完成了。由以上的分析可以看出,構(gòu)造函數(shù)實(shí)現(xiàn)了對(duì)象的初始化和賦值兩個(gè)過程:對(duì)象的初始化是通過初始化列表來完成,而對(duì)象的賦值則才是通過構(gòu)造函數(shù),或者更準(zhǔn)確的說應(yīng)該是構(gòu)造函數(shù)的實(shí)現(xiàn)體。

虛函數(shù)表指針(VTable Pointer)
我 們?cè)趺纯赡軙?huì)忽視虛函數(shù)表指針呢?如果沒有它的話,C++世界會(huì)清凈很多。我們最關(guān)心的是對(duì)于那些擁有虛函數(shù)的類,它們的類對(duì)象中的虛函數(shù)表指針是什么時(shí) 候賦值的?我們沒有任何代碼,也沒有任何能力(當(dāng)然暴力破解的方法除外)能夠在類對(duì)象創(chuàng)建的時(shí)候給其虛表指針賦值,給虛表指針賦值是編譯器偷偷完成的,具 體的時(shí)機(jī)是在進(jìn)入到虛函數(shù)后,在給對(duì)象的數(shù)據(jù)成員初始化和賦值之前,編譯器偷偷的給虛表指針賦值。下面我們就看看具體的情況是什么樣的吧。在上面的 CJdBase類的基礎(chǔ)上再添加一個(gè)虛函數(shù):     class CJdBase {
    public:
        CJdBase::CJdBase(int id):m_innerObj(id),m_iID(id){
            m_innerObj = 10;
        }
    public:
        virtual void dumpMe() {}
    private:
        CInnerClass m_innerObj;
        int m_iID;
    };使用VS2002編譯獲得這個(gè)構(gòu)造函數(shù)的匯編代碼,其中最關(guān)鍵的一些代碼如下:     mov    DWORD PTR _this$[ebp], ecx
    mov    eax, DWORD PTR _this$[ebp]
    mov    DWORD PTR [eax], OFFSET FLAT:??_7CJdBase@@6B@
    mov    eax, DWORD PTR _id$[ebp]
    push    eax
    mov    ecx, DWORD PTR _this$[ebp]
    add    ecx, 4
    call    ??0CInnerClass@@QAE@H@Z            ; CInnerClass::CInnerClass
    mov    eax, DWORD PTR _this$[ebp]
    mov    ecx, DWORD PTR _id$[ebp]
    mov    DWORD PTR [eax+8], ecx

; 5    :     m_innerObj = 10;

    push    10                    ; 0000000aH
    lea    ecx, DWORD PTR $T1368[ebp]
    call    ??0CInnerClass@@QAE@H@Z            ; CInnerClass::CInnerClass
    lea    eax, DWORD PTR $T1368[ebp]
    push    eax
    mov    ecx, DWORD PTR _this$[ebp]
    add    ecx, 4
    call    ??4CInnerClass@@QAEAAV0@ABV0@@Z        ; CInnerClass::operator=從這些代碼中的 mov    DWORD PTR [eax], OFFSET FLAT:??_7CJdBase@@6B@我們可以清晰的看到,在構(gòu)造函數(shù)的最開始,在進(jìn)入構(gòu)造函數(shù)體內(nèi)部,甚至是在進(jìn)入初始化列表之前,編譯器會(huì)插入代碼用當(dāng)前正在被構(gòu)造的類的虛表地址給虛表指針賦值。

后記
如果不是親自實(shí)踐和分析,很難想象一個(gè)簡(jiǎn)單的類對(duì)象創(chuàng)建過程竟然蘊(yùn)涵了這么多秘密。了解了這些秘密為我們解決其他的一些問題打開了勝利之門。
試試下面的一些問題,不知道在你看完本文后是否能夠有一種豁然開朗的感覺:
    1. 為什么C++需要提供初始化列表?那些情況下必須實(shí)現(xiàn)初始化列表? (提示:有些情況下只能初始化不能賦值)
    2. 構(gòu)造函數(shù)可以是虛函數(shù)呢?在構(gòu)造函數(shù)中調(diào)用虛函數(shù)會(huì)有什么樣的結(jié)果? (提示:虛表指針是在構(gòu)造函數(shù)的最開始初始化的)
    3. 構(gòu)造函數(shù)和賦值操作符operator=有什么區(qū)別? (提示:區(qū)分初始化和賦值)

歷史記錄
07/29/2007   v1.0
原文的第一版


本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/eroswang/archive/2007/08/04/1725640.aspx

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多