專業(yè)微信網(wǎng)站建設(shè)公司首選公司哪家好互聯(lián)網(wǎng)推廣公司排名
目錄:
一、拷貝構(gòu)造
(一)拷貝函數(shù)的特點(diǎn)
二、賦值運(yùn)算符重載
(一)運(yùn)算符重載
(二)賦值運(yùn)算符重載
正文
一、拷貝構(gòu)造
如果一個(gè)構(gòu)造函數(shù)的第一個(gè)參數(shù)是自身類類型的引用,且任何額外的參數(shù)都有默認(rèn)值,此構(gòu)造函數(shù)也叫做拷貝構(gòu)造函數(shù),也就是說拷貝構(gòu)造是一個(gè)特殊的構(gòu)造函數(shù)。
(一)拷貝函數(shù)的特點(diǎn)
(1)拷?構(gòu)造函數(shù)是構(gòu)造函數(shù)的?個(gè)重載(函數(shù)名相同,參數(shù)類型/個(gè)數(shù)不同即可構(gòu)成重載)
在理解構(gòu)造函數(shù)的前提下,拷貝構(gòu)造的寫法和構(gòu)造函數(shù)的區(qū)別在于參數(shù)類型的不同(看不懂拷貝構(gòu)造參數(shù)的類型沒事,下面會(huì)講)根據(jù)定義:函數(shù)名相同,參數(shù)類型/個(gè)數(shù)不同即可構(gòu)成重載。
(2)拷?構(gòu)造函數(shù)的參數(shù)只有?個(gè)且必須是類類型對(duì)象的引?,使?傳值?式編譯器直接報(bào)錯(cuò),因?yàn)檎Z法邏輯上會(huì)引發(fā)?窮遞歸調(diào)?。(不理解參數(shù)為什么這樣寫沒關(guān)系,下面會(huì)解釋先記住樣)
對(duì)于傳參有三種方式:傳值、傳址、傳引用。一般有傳引用就不用傳址了,因?yàn)楦鼉?yōu)。
不能用傳值是因?yàn)樾螀⑹菍?shí)參的一份臨時(shí)拷貝,函數(shù)結(jié)束就銷毀不影響實(shí)參,拷貝構(gòu)造函數(shù)要實(shí)實(shí)在在的進(jìn)行兩個(gè)對(duì)象值的拷貝就不能引用傳值。
(3)C++規(guī)定自定義類型對(duì)象進(jìn)行拷貝行為必須調(diào)用拷貝構(gòu)造,所以這??定義類型傳值傳參和傳值返回都會(huì)調(diào)?拷?構(gòu)造完成。
傳值返回會(huì)調(diào)是因?yàn)?#xff1a;返回值并不是我們所看到的返回某個(gè)變量類型而已,真實(shí)操作系統(tǒng)會(huì)把返回值先放在寄存器里,函數(shù)結(jié)束釋放空間后將寄存器里的值再傳回來。這個(gè)過程需要拷貝值到寄存器。
(4)若未顯式定義拷?構(gòu)造,編譯器會(huì)?成?動(dòng)?成拷?構(gòu)造函數(shù)。?動(dòng)?成的拷?構(gòu)造對(duì)內(nèi)置類型成員變量會(huì)完成值拷?/淺拷?(?個(gè)字節(jié)?個(gè)字節(jié)的拷?),對(duì)?定義類型成員變量會(huì)調(diào)?他的拷?構(gòu)造。
(5)像Date這樣的類成員變量全是內(nèi)置類型且沒有指向什么資源,編譯器?動(dòng)?成的拷?構(gòu)造就可以完成需要的拷?,所以不需要我們顯?實(shí)現(xiàn)拷?構(gòu)造。這?還有?個(gè)?技巧,如果?個(gè)類顯?實(shí)現(xiàn)了析構(gòu)并釋放資源,那么他就 需要顯?寫拷?構(gòu)造,否則就不需要。什么時(shí)候需要自己寫拷貝構(gòu)造,就是當(dāng)你內(nèi)置類型或自定義類型有指向資源時(shí)一定要自己寫拷貝構(gòu)造(資源:動(dòng)態(tài)內(nèi)存開辟的空間、打開的文件、棧、堆....)
(6)傳值引?返回,返回的是返回對(duì)象的別名(引?),沒有產(chǎn)?拷?。但是如果返回對(duì)象是?個(gè)當(dāng)前函數(shù)局部域的局部對(duì)象,函數(shù)結(jié)束就銷毀了,那么使?引?返回是有問題的,這時(shí)的引?相當(dāng)于?個(gè)野引?,類似?個(gè)野指針?樣。傳引?返回可以減少拷?,但是?定要確保返回對(duì)象,在當(dāng)前函數(shù)結(jié)束后還在,才能?引?返回。
用一個(gè)對(duì)象拷貝構(gòu)造出另一個(gè)對(duì)象時(shí)為什么用引用?
要證明這個(gè)問題得從不用引用會(huì)如何說起
(如下圖)如果不用引用,那么調(diào)用拷貝構(gòu)造函數(shù)前將d1的值傳給形參d是值傳遞,系統(tǒng)規(guī)定傳值調(diào)用和傳值返回會(huì)自動(dòng)調(diào)用拷貝構(gòu)造,也就是當(dāng)你把d1傳給d時(shí)得先把d1中的值通過拷貝構(gòu)造拷貝給d(把d創(chuàng)造出來)有了d再調(diào)用拷貝構(gòu)造函數(shù)Date( Date& d)
而當(dāng)你每次要調(diào)用拷貝構(gòu)造就要先傳值,傳值中途又會(huì)調(diào)用拷貝構(gòu)造將d1值拷貝給d,一直循環(huán)反復(fù)就構(gòu)成死循環(huán)(看下圖)一直回不到你最初要調(diào)用的拷貝構(gòu)造函數(shù)。引用就不一樣了,引用不會(huì)額外開辟空間圖中d是d1的別名,修改d等于直接修改d1同時(shí)還避免了值傳遞在中途調(diào)用拷貝構(gòu)造函數(shù)!
(此圖是傳值調(diào)用,用來證明為什么需要引用調(diào)用)
特別提醒:類的每個(gè)成員函數(shù)的第一個(gè)參數(shù)是this指針,不能顯示寫但是可以顯示調(diào)用。調(diào)用拷貝構(gòu)造實(shí)際是將d2傳給了this指針,d1傳給了d。所以函數(shù)體內(nèi)就是把d1的值拷貝構(gòu)造出d2,可寫成this-> d._year =? year 或?_year = d._ year。
因此拷貝構(gòu)造函數(shù)的參數(shù)有兩個(gè),只是this沒顯示寫;拷貝構(gòu)造是用一個(gè)已存在的對(duì)象構(gòu)造出另一個(gè)對(duì)象!!
為什么加const?
正規(guī)的寫法在參數(shù)前面會(huì)加const。沒加不影響當(dāng)為什么要加?
其實(shí)只要涉及引用就最好加加一下,因?yàn)?#xff08;1)引用可以改變指向?qū)ο蟮闹?#xff0c;怕被誤改(2)權(quán)限問題,防止實(shí)參本身是const變量,若是不加權(quán)限放大報(bào)錯(cuò),加const可以權(quán)限縮小和平移但不能權(quán)限放大。
我們要是不寫拷貝構(gòu)造,編譯器生成的行為是什么?
對(duì)于內(nèi)置類型進(jìn)行值拷貝/淺拷貝,自定義類型調(diào)用它自己的拷貝構(gòu)造。涉及深淺拷貝
淺拷貝就是對(duì)應(yīng)一個(gè)字節(jié)一個(gè)字節(jié)的拷貝過去,深拷貝是當(dāng)你這個(gè)變量有指向一塊空間時(shí),像動(dòng)態(tài)開辟的、數(shù)組等,要先一模一樣開辟一塊空間出來,再把里面數(shù)據(jù)拷貝過來叫深拷貝。
二、賦值運(yùn)算符重載
(一)運(yùn)算符重載
兩個(gè)數(shù)之間的運(yùn)算有+-*/%……,兩個(gè)類類型要進(jìn)行運(yùn)算就不能用普通的運(yùn)算符了,C++語?允許我們通過運(yùn)算符重載的形式指定新的運(yùn)算含義。
運(yùn)算符重載用法:
(1)運(yùn)算符重載是由operator和后?要定義的運(yùn)算符共同構(gòu)成。它的返回值由兩個(gè)類類型的對(duì)象運(yùn)算后結(jié)果的類型決定,例如兩個(gè)類類型中成員判斷是否相等返回是布爾值,返回類型為bool;兩個(gè)類類型中成員相減/加結(jié)果為一個(gè)整數(shù)返回類型為int;
只要涉及傳參就會(huì)自動(dòng)調(diào)用拷貝構(gòu)造,所以這里用引用,用了引用最好加上const,防止誤改和權(quán)限問題報(bào)錯(cuò)(參考上面用一個(gè)對(duì)象拷貝構(gòu)造出另一個(gè)對(duì)象時(shí)為什么用引用的講解)
(2)重載運(yùn)算符函數(shù)的參數(shù)個(gè)數(shù)和該運(yùn)算符作?的運(yùn)算對(duì)象數(shù)量?樣多。?元運(yùn)算符(單目運(yùn)算符)有?個(gè)參數(shù)(操作數(shù)),?元運(yùn)算符(雙目運(yùn)算符)有兩個(gè)參數(shù)(操作數(shù))
(3)如果?個(gè)重載運(yùn)算符函數(shù)是成員函數(shù),則它的第?個(gè)運(yùn)算對(duì)象默認(rèn)傳給隱式的this指針,因此運(yùn)算符重載作為成員函數(shù)時(shí),參數(shù)?運(yùn)算對(duì)象少?個(gè)。
(4)運(yùn)算符重載以后,其優(yōu)先級(jí)和結(jié)合性不變。
(5).* ?::? sizeof? ?:? . 注意以上5個(gè)運(yùn)算符不能重載。重載操作符?少有?個(gè)類類型參數(shù),不能通過運(yùn)算符重載改變內(nèi)置類型對(duì)象的含義,如: int operator+(int x, int y)
調(diào)用類成員函數(shù)需要用到.*操作符
(6)重載++運(yùn)算符時(shí),有前置++和后置++,運(yùn)算符重載函數(shù)名都是operator++,?法很好的區(qū)分。C++規(guī)定,后置++重載時(shí),增加?個(gè)int形參,跟前置++構(gòu)成函數(shù)重載,?便區(qū)分。只要是個(gè)整型就行。
(二)賦值運(yùn)算符重載
賦值運(yùn)算符重載是?個(gè)默認(rèn)成員函數(shù)(就是把運(yùn)算符重載放到類的public下生成),?于完成兩個(gè)已經(jīng)存在的對(duì)象直接的拷?賦值,這?要注意跟拷?構(gòu)造區(qū)分,拷?構(gòu)造?于?個(gè)對(duì)象拷?初始化給另?個(gè)要?jiǎng)?chuàng)建的對(duì)象。
賦值運(yùn)算符重載的特點(diǎn):
(1)賦值運(yùn)算符重載是?個(gè)運(yùn)算符重載,規(guī)定必須重載為成員函數(shù)(在類中)。賦值運(yùn)算重載的參數(shù)建議寫成const 當(dāng)前類類型引?,否則會(huì)傳值傳參會(huì)有拷?。?
例如下圖:日期類中已經(jīng)存在的d1、d3對(duì)象,將d3賦值給d1調(diào)用賦值重載。d1傳給隱式的this指針,d3傳給d,兩個(gè)對(duì)象賦值之后返回的是d1對(duì)象所以返回值為Date類,d1存在this中。為了避免自己給自己賦值導(dǎo)致不必要的問題,在交換前先判斷地址是否是同一個(gè)對(duì)象。
(2)有返回值,且建議寫成當(dāng)前類類型引?,引?返回可以提?效率,有返回值?的是為了?持連續(xù)賦值場(chǎng)景。
(3)賦值重載沒有顯式實(shí)現(xiàn)時(shí),編譯器會(huì)自動(dòng)?成?個(gè)默認(rèn)賦值運(yùn)算符重載,默認(rèn)賦值運(yùn)算符重載?為跟默認(rèn)構(gòu)造函數(shù)類似,對(duì)內(nèi)置類型成員變量會(huì)完成值拷貝/淺拷貝(?個(gè)字節(jié)?個(gè)字節(jié)的拷貝),對(duì)自定義類型成員變量會(huì)調(diào)用他的拷貝構(gòu)造。
因?yàn)閮?nèi)置類型是語言自己定義的類型,存的值比較簡(jiǎn)單,可直接轉(zhuǎn)成指令進(jìn)行操作不用賦值運(yùn)算符重載。如果?個(gè)類顯示實(shí)現(xiàn)了析構(gòu)并釋放資源,那么他就需要顯示寫賦值運(yùn)算符重載,否則就不需要。
賦值重載的深度拷貝是將d1原本資源空間先free掉,再開辟一塊和d3一樣大的空間給d1,然后再把d3里面的值拷貝過去。所以要判斷是否是自己給自己賦值,不然把自己free了還給自己賦值是個(gè)大坑!!
小提示:
對(duì)以上全部內(nèi)容大家多理解幾遍一定能學(xué)會(huì),要相信自己的學(xué)習(xí)能力。
完