13 類和對象--初始化和清理

構(gòu)造函數(shù)和析構(gòu)函數(shù)

2個函數(shù)分別用于對象的初始化和清理,如果我們自己不提供函數(shù)方法,編譯器會提供默認(rèn)的方法,但是里面的內(nèi)容為空實(shí)現(xiàn)

構(gòu)造函數(shù)為創(chuàng)建對象時,給對象初始化屬性賦值。方法名和類名一樣,參數(shù)可以為空或者有參數(shù)列表,可以重載,構(gòu)造方法只會調(diào)用一次,沒有返回值即void類型(但這個void不用我們寫)

析構(gòu)函數(shù)在對象被銷毀前調(diào)用。方法名在構(gòu)造前加個~波浪號,析構(gòu)函數(shù)不可以有參數(shù),只會調(diào)用一次,同樣不可寫返回類型(即不用寫return)

1

如上,我們分別定義了構(gòu)造和析構(gòu),構(gòu)造是我們Person p那里調(diào)用,而析構(gòu)是我們按任意鍵退出時調(diào)用

構(gòu)造函數(shù)的分類和調(diào)用

按照有無參數(shù)可以分為有參和無參構(gòu)造,編譯器默認(rèn)提供的就是無參構(gòu)造

2

如上,p1為無參構(gòu)造,p2為有參構(gòu)造,有參和無參對應(yīng)的就是構(gòu)造方法的重載

按照構(gòu)造方法傳參可以分為普通構(gòu)造和拷貝構(gòu)造,普通就不用說了,這里看下拷貝構(gòu)造

3

拷貝構(gòu)造本質(zhì)就是想把已經(jīng)創(chuàng)建的該類對象進(jìn)行屬性拷貝,但是由于不想改變原單位,所以使用const常量修飾,同時使用引用不開辟額外空間

構(gòu)造方法的調(diào)用分為隱式法,顯示法,括號法? 3種

4

如上為括號法,當(dāng)無參不能寫括號,有參傳入指定參數(shù),p3使用了拷貝構(gòu)造,是在對象名后加括號

5

如果括號法無參加了括號,會發(fā)現(xiàn)沒有實(shí)例,這是因?yàn)闀徽J(rèn)為是個函數(shù)的聲明

顯示法

6

如上,我們分別使用了顯示法,顯示法本質(zhì)就是構(gòu)造方法函數(shù)的調(diào)用。

這里Person()等號右側(cè)的部分單寫相當(dāng)于是個匿名對象,如果不給左側(cè)賦值,編譯器執(zhí)行完這行就會銷毀,如下

7

匿名對象注意事項(xiàng),使用匿名對象不要使用拷貝,會報(bào)錯,因?yàn)闀牙ㄌ柨闯墒鞘÷?,認(rèn)為重新定義了對象

8

隱式構(gòu)造,自動進(jìn)行構(gòu)造識別

9

如上,我們定義Person p1 = 10;看著好像左右2側(cè)類型不一致該報(bào)錯,但是因?yàn)榉嫌袇?gòu)造輸入,所以是可以執(zhí)行的,相當(dāng)于進(jìn)行了有參構(gòu)造

如上分析,還是顯示法比較好理解且不容易出現(xiàn)錯誤。

拷貝構(gòu)造函數(shù)調(diào)用時機(jī)

拷貝構(gòu)造我們知道可以直接復(fù)制已有對象屬性創(chuàng)建新對象。其還有在函數(shù)值傳遞時和函數(shù)返回類對象時被調(diào)用

10

如上,是值傳遞對象給方法,我們給方法傳入?yún)?shù)p,本質(zhì)是將p傳給拷貝函數(shù)進(jìn)行調(diào)用

11

將類函數(shù)內(nèi)局部類對象返回時,本質(zhì)也調(diào)用了拷貝構(gòu)造,我們可以查看地址,顯示出來的地址不同,圖中的析構(gòu)是局部變量的析構(gòu)執(zhí)行

構(gòu)造函數(shù)的調(diào)用規(guī)則

默認(rèn)情況下,編譯器會給類添加3個無參,有參(有參和無參函數(shù)體為空),拷貝(默認(rèn)自動將全部屬性拷貝)的構(gòu)造方法

12

如上,我們可以看到拷貝會自動拷貝值,雖然我們沒指定哪些,默認(rèn)的會將屬性全部拷貝

如果我們只寫有參構(gòu)造,則默認(rèn)無參構(gòu)造方法失效,但拷貝構(gòu)造依然有效

13

如上,我們定義了有參構(gòu)造,默認(rèn)無參構(gòu)造就沒有了

如果只寫拷貝構(gòu)造函數(shù),則默認(rèn)的無參和有參都無效(對象都不能好好創(chuàng)建了)

深拷貝和淺拷貝

淺拷貝:簡單的賦值拷貝操作

深拷貝:堆區(qū)重新申請空間,拷貝操作

14

我們?nèi)缟?,使用默認(rèn)的拷貝構(gòu)造,默認(rèn)是使用的淺拷貝,即p1里面的賦值都拷貝到p2里,然而這樣就會出現(xiàn)問題

15

如上,我們之前的屬性是在棧區(qū)開辟,如果我們給屬性在堆區(qū)開辟,使用new方法,如上,有參構(gòu)造使用指針接收,再在析構(gòu)方法里delete釋放,這里判斷下height指針是否為空,如果不為空就刪掉,讓其置為NULL,看起來邏輯好像沒錯,但是運(yùn)行上面的程序就會報(bào)錯

16

這里是為什么呢,淺拷貝將指針的內(nèi)容也拷貝了過去,所以p1,p2的height都是指向一個堆地址,當(dāng)p1釋放,此堆區(qū)被置不可用,但是p2析構(gòu)還是會調(diào)用釋放,p2的height指針還指向這個地方,然而已經(jīng)不能誒調(diào)用,所以報(bào)錯,即淺拷貝帶來堆區(qū)內(nèi)容重復(fù)釋放

為了不出現(xiàn)這個異常,我們就要自定義拷貝構(gòu)造,使用深拷貝,讓指針指向新開辟地址

17

如上,我們在拷貝函數(shù)里age還是賦值,但是對于指向堆區(qū)的指針要重新賦值,*p.height是因?yàn)閔eight為指針,要解引用獲得值

所以有在堆區(qū)開辟的屬性,一定要在拷貝構(gòu)造函數(shù)里使用深拷貝

初始化列表

除了構(gòu)造方法,對于類還有初始化列表的操作實(shí)現(xiàn)初始化屬性

18

如上,格式是在構(gòu)造方法參數(shù)小括號后使用:參數(shù)名(初始值)中間逗號分隔的形式,如上,就實(shí)現(xiàn)了無參初始化給屬性賦值10,20,30

19

同理有參構(gòu)造可以使用如上,即將參數(shù)給屬性的括號里

類對象作為類屬性成員

20

如上,我們定義個Person類,有name和Phone屬性,Phone又是額外的類,這里我們就用到前面的參數(shù)列表初始化,有人會問了,我們的phone(b)不是相當(dāng)于Phone phone = b嗎,左側(cè)是手機(jī),右側(cè)是字符串,這里用了隱式轉(zhuǎn)換,因?yàn)镻hone有有參的構(gòu)造符合。同時我們可以分析下構(gòu)造和析構(gòu)的順序

21

我們構(gòu)造就不用說了,手機(jī)的構(gòu)造在人構(gòu)造前,因?yàn)閰?shù)傳參過程就調(diào)用了手機(jī)構(gòu)造,而析構(gòu)的順序是和構(gòu)造相反的

靜態(tài)成員

靜態(tài)成員就是類成員加上static修飾,分為靜態(tài)屬性和靜態(tài)方法

靜態(tài)屬性,所有對象共享一個區(qū)域,編譯階段已分配內(nèi)存,類內(nèi)聲明,類外初始化

靜態(tài)方法,所有對象享用一個方法,只能訪問靜態(tài)變量,不能訪問非靜態(tài)變量

22

如上,我們定義靜態(tài)變量age,加了static聲明,但是初始化不能寫在類內(nèi)部,因?yàn)槎鄬ο蠊蚕?,所以我們可以看到他們的age地址是一個,類外初始化時,使用數(shù)據(jù)類型 類名::屬性名 = 屬性值;

23

靜態(tài)方法可以訪問靜態(tài)變量,調(diào)用課可以用過對象.訪問,也可以通過類名::訪問,靜態(tài)方法不能訪問非靜態(tài)變量,因?yàn)殪o態(tài)方法是編譯時已內(nèi)存中生成,而非靜態(tài)的是創(chuàng)建對象時才定義,并不關(guān)聯(lián)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容