深度分析C++默認構造函數、拷貝構造函數

對於C++初學者來說,時常不難看到他們說:
1.任何class如果沒有定義默認構造函數,那麼就會由編譯器來合成一個出來。
2.編譯器合成來的構造函數會明確確定裏面所有成員的值。(比如int類型成員會初始化成0)
呃,這當然是一部分C++新手的一廂情願吧、其實C++裏面對於構造函數的誕生與否是取決於編譯器是否需要必須要爲其產生構造函數。。。或者說是有點類似被迫不得已時候,編譯器纔會合成構造函數。這是第一點。
第二點,只有編譯器迫不得已時候,纔會幫你初始化某些成員,而絕對不是所有成員都進行初始化。
無論如何也好吧,請記住這個詞:迫不得已時候。
舉個例子吧
class A{private:int mdata;}
就是這樣的類,假設沒有任何構造函數,那麼當我們聲明一個對象 A x;時候,會不會產生構造函數?會不會有mdata的0初始化發生?
答案是:沒有任何構造函數被合成,就算假設有,好吧,我加粗了假設,再次強調是假設有,也不會初始化成0。還記得我們剛剛說的那個詞語麼?迫不得已,我們可以這樣想,C語言裏面 A x;這樣子的結構體也是可行的,那麼我們就沒有把編譯器逼到迫不得已的地步,或者想《深度探索C++對象模型》這本神書說的一樣,這是程序員的職責去寫構造函數,去初始化。這個和編譯器沒有半毛關係。。
那麼,什麼事情纔算是迫不得已讓編譯器合成構造函數呢?構造函數的合成是類似什麼都不做?還是另有一番洞天? = = !
1.成員對象具有默認構造函數,這時候編譯器就無法再去偷懶了,生活已經把懶惰的它強迫到要去合成代碼的地步了,怎麼說呢?或者我們可以這樣想吧。假設成員對象裏面有一個蛋疼的功能是申請堆資源。假設編譯器不幫這個類合成構造函數,那麼悲催的類中某一個成員對象生來就沒有申請到堆資源。。。這樣就很莫名其妙的,對嗎?
呃,問題又來了,所謂的合成代碼是值什麼合成呢?它是怎麼合成的呢?假設有1000個cpp文件,每個文件都有這個沒有構造函數的類的定義,都要用到這個定義的類,那麼編譯器是如何分別給1000個文件去合成這個類的構造函數呢?呃,編譯器是這樣做的,如果文件中存在着類對象的定義,那麼就必須要付出合成代碼的代價。。。這時候採取的合成代碼是儘量使用 inline方式合成。要是一些莫名其妙的代碼,真的是無法用inline合成了,就採取static合成,呃,其實inline也好,static也好,都是爲了避免產生多個全局的符號。。。你懂得,1000個全局符號,這個鏈接器估計也得受不了吧。。。目測得符號拋出符號重定義錯誤,畢竟是1000個強符號啊…..
呃,問題又來了。。構造函數將會擴充成什麼樣子?或者這樣說吧。。。它初始化一些什麼東西?偷偷幫什麼成員進行了默認構造函數的調動。答案是:對內置類型,像什麼int double 鳥都不鳥他們,噢,那些沒有構造函數的類,看起來有點像C語言的結構體吧。。。C語言都不鳥它,那麼C’++幹嘛要鳥他?對吧。。。所以對於帶有構造函數的成員對象,纔會被構造函數偷偷的初始化,即使偷懶的程序員沒有初始化他們!!編譯器也得做!具體原因見上面再上面幾行加粗的字體。。。好好讀讀。編譯器是懶惰的,迫不得已時候纔會對其進行改變。。。。
呃。。。這是最後一個問題了吧。。。構造函數函數對成員的初始化順序是和什麼有關的?A 構造函數參數列表?B 成員對象聲明次序?
答案是B。。。又到了要說爲什麼然後解釋的時候。。。簡單的一個反證法就可以想出來了,假設是A,那麼對於一些不帶構造函數參數列表的類,是不是就不對帶有構造函數的成員對象初始化?這不科學吧???
2.帶有構造函數的基類。。道理有點類似啊,要是派生類繼承了基類,基類再構造函數裏面申請堆資源。。。那麼作爲派生類,是否應該把應該屬於你的資源找回來????或者舉例子說吧,按照人的語言,公有繼承是表達 “是”的意思,假設老師繼承了人,人有吃飯的屬性,在構造函數裏實現了,然後老師繼承了人,但是沒有調動構造函數,老師變成了只會領取工資不會吃飯的人。。。。— —!
3.帶有虛指針的類
這個怎麼說呢,也是反證法!!!!!!假設編譯器傻不拉幾的把這個類忽略了,不再爲它合成構造函數,那麼會有什麼後果?毫無疑問!!!!vfptr那些東東全部都是0xCCCCCCCC(棧)或者0xCDCDCDCD(堆)。。。。編譯器意思說,愚蠢的程序員,你自己來重置虛表吧!!!然後這個編譯器就被程序員輸入 kill -9殺掉了。。。好吧!!!重點來了!
兩個擴張操作會在編譯期間完成!
a.編譯器爲了支持基類指針指向派生類對象,實現多態,必須要在編譯期把虛表這些都搞出來。。。地址填好
b.噢,每一個類對象裏面,都要給他們塞進一個指針,讓他們指向那個虛表。。。
記住了,我們編譯器爲了不被程序員kill掉做了太多太多的東西了。。。真是可憐的編譯器
4.帶有虛基類的類,呃。虛繼承意思是共享繼承的意思。。。因爲對應菱形繼承結構可能會存在C裏面有兩個X的類。。。呃,要是再往下數據冗餘會更加嚴重。。。這時候就引入了虛繼承這個概念了
這裏寫圖片描述
— — !長話短說!虛繼承破壞了純C的那個存儲結構,如果編譯器不按照一定的只能去恢復構造功能,那麼就將會很詫異了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章