資源描述:
《第9章 類的構(gòu)造函數(shù)、析構(gòu)函數(shù)與賦值函數(shù)》由會員上傳分享,免費(fèi)在線閱讀,更多相關(guān)內(nèi)容在行業(yè)資料-天天文庫。
1、第9章類的構(gòu)造函數(shù)、析構(gòu)函數(shù)與賦值函數(shù)構(gòu)造函數(shù)、析構(gòu)函數(shù)與賦值函數(shù)是每個類最基本的函數(shù)。它們太普通以致讓人容易麻痹大意,其實(shí)這些貌似簡單的函數(shù)就象沒有頂蓋的下水道那樣危險(xiǎn)。每個類只有一個析構(gòu)函數(shù)和一個賦值函數(shù),但可以有多個構(gòu)造函數(shù)(包含一個拷貝構(gòu)造函數(shù),其它的稱為普通構(gòu)造函數(shù))。對于任意一個類A,如果不想編寫上述函數(shù),C++編譯器將自動為A產(chǎn)生四個缺省的函數(shù),如A(void);//缺省的無參數(shù)構(gòu)造函數(shù)A(constA&a);//缺省的拷貝構(gòu)造函數(shù)~A(void);//缺省的析構(gòu)函數(shù)A&operate=(constA
2、&a);//缺省的賦值函數(shù)這不禁讓人疑惑,既然能自動生成函數(shù),為什么還要程序員編寫?原因如下:(1)如果使用“缺省的無參數(shù)構(gòu)造函數(shù)”和“缺省的析構(gòu)函數(shù)”,等于放棄了自主“初始化”和“清除”的機(jī)會,C++發(fā)明人Stroustrup的好心好意白費(fèi)了。(2)“缺省的拷貝構(gòu)造函數(shù)”和“缺省的賦值函數(shù)”均采用“位拷貝”而非“值拷貝”的方式來實(shí)現(xiàn),倘若類中含有指針變量,這兩個函數(shù)注定將出錯。對于那些沒有吃夠苦頭的C++程序員,如果他說編寫構(gòu)造函數(shù)、析構(gòu)函數(shù)與賦值函數(shù)很容易,可以不用動腦筋,表明他的認(rèn)識還比較膚淺,水平有待于提高
3、。本章以類String的設(shè)計(jì)與實(shí)現(xiàn)為例,深入闡述被很多教科書忽視了的道理。String的結(jié)構(gòu)如下:classString{public:String(constchar*str=NULL);//普通構(gòu)造函數(shù)String(constString&other);//拷貝構(gòu)造函數(shù)~String(void);//析構(gòu)函數(shù)String&operate=(constString&other);//賦值函數(shù)private:char*m_data;//用于保存字符串};9.1構(gòu)造函數(shù)與析構(gòu)函數(shù)的起源作為比C更先進(jìn)的語言,C++提供
4、了更好的機(jī)制來增強(qiáng)程序的安全性。C++編譯器具有嚴(yán)格的類型安全檢查功能,它幾乎能找出程序中所有的語法問題,這的確幫了程序員的大忙。但是程序通過了編譯檢查并不表示錯誤已經(jīng)不存在了,在“錯誤”的大家庭里,“語法錯誤”的地位只能算是小弟弟。級別高的錯誤通常隱藏得很深,就象狡猾的罪犯,想逮住他可不容易。根據(jù)經(jīng)驗(yàn),不少難以察覺的程序錯誤是由于變量沒有被正確初始化或清除造成的,而初始化和清除工作很容易被人遺忘。Stroustrup在設(shè)計(jì)C++語言時充分考慮了這個問題并很好地予以解決:把對象的初始化工作放在構(gòu)造函數(shù)中,把清除工作
5、放在析構(gòu)函數(shù)中。當(dāng)對象被創(chuàng)建時,構(gòu)造函數(shù)被自動執(zhí)行。當(dāng)對象消亡時,析構(gòu)函數(shù)被自動執(zhí)行。這下就不用擔(dān)心忘了對象的初始化和清除工作。構(gòu)造函數(shù)與析構(gòu)函數(shù)的名字不能隨便起,必須讓編譯器認(rèn)得出才可以被自動執(zhí)行。Stroustrup的命名方法既簡單又合理:讓構(gòu)造函數(shù)、析構(gòu)函數(shù)與類同名,由于析構(gòu)函數(shù)的目的與構(gòu)造函數(shù)的相反,就加前綴‘~’以示區(qū)別。除了名字外,構(gòu)造函數(shù)與析構(gòu)函數(shù)的另一個特別之處是沒有返回值類型,這與返回值類型為void的函數(shù)不同。構(gòu)造函數(shù)與析構(gòu)函數(shù)的使命非常明確,就象出生與死亡,光溜溜地來光溜溜地去。如果它們有返回
6、值類型,那么編譯器將不知所措。為了防止節(jié)外生枝,干脆規(guī)定沒有返回值類型。(以上典故參考了文獻(xiàn)[Eekel,p55-p56])9.2構(gòu)造函數(shù)的初始化表構(gòu)造函數(shù)有個特殊的初始化方式叫“初始化表達(dá)式表”(簡稱初始化表)。初始化表位于函數(shù)參數(shù)表之后,卻在函數(shù)體{}之前。這說明該表里的初始化工作發(fā)生在函數(shù)體內(nèi)的任何代碼被執(zhí)行之前。構(gòu)造函數(shù)初始化表的使用規(guī)則:u如果類存在繼承關(guān)系,派生類必須在其初始化表里調(diào)用基類的構(gòu)造函數(shù)。例如classA{…A(intx);//A的構(gòu)造函數(shù)};classB:publicA{…B(intx,i
7、nty);//B的構(gòu)造函數(shù)};B::B(intx,inty):A(x)//在初始化表里調(diào)用A的構(gòu)造函數(shù){…}u類的const常量只能在初始化表里被初始化,因?yàn)樗荒茉诤瘮?shù)體內(nèi)用賦值的方式來初始化(參見5.4節(jié))。u類的數(shù)據(jù)成員的初始化可以采用初始化表或函數(shù)體內(nèi)賦值兩種方式,這兩種方式的效率不完全相同。非內(nèi)部數(shù)據(jù)類型的成員對象應(yīng)當(dāng)采用第一種方式初始化,以獲取更高的效率。例如classA{…A(void);//無參數(shù)構(gòu)造函數(shù)A(constA&other);//拷貝構(gòu)造函數(shù)A&operate=(constA&other)
8、;//賦值函數(shù)};classB{public:B(constA&a);//B的構(gòu)造函數(shù)private:Am_a;//成員對象};示例9-2(a)中,類B的構(gòu)造函數(shù)在其初始化表里調(diào)用了類A的拷貝構(gòu)造函數(shù),從而將成員對象m_a初始化。示例9-2(b)中,類B的構(gòu)造函數(shù)在函數(shù)體內(nèi)用賦值的方式將成員對象m_a初始化。我們看到的只是一條賦值語句,但實(shí)際上B的構(gòu)造函數(shù)干