版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第5章結(jié)構(gòu)和析構(gòu)函數(shù)結(jié)構(gòu)函數(shù)和析構(gòu)函數(shù)引入帶參結(jié)構(gòu)函數(shù)和默認(rèn)結(jié)構(gòu)函數(shù)組員初始化列表拷貝結(jié)構(gòu)函數(shù)對(duì)象結(jié)構(gòu)次序再看new和delete第1頁5.1結(jié)構(gòu)函數(shù)-背景與結(jié)構(gòu)和其它基本數(shù)據(jù)類型變量一樣:定義一個(gè)全局對(duì)象會(huì)將其所占內(nèi)存空間清0定義一個(gè)局部對(duì)象時(shí),不會(huì)執(zhí)行任何初始化動(dòng)作,其數(shù)據(jù)組員值完全依賴于堆棧上情況。對(duì)象應(yīng)該表示了現(xiàn)實(shí)世界中對(duì)應(yīng)實(shí)體,一旦建立對(duì)象,其每個(gè)數(shù)據(jù)組員理應(yīng)有合理初始值。第2頁5.1結(jié)構(gòu)函數(shù)-背景structRectangle{doublefWidth;doublefHeight;};classStudent{public:intGetAge()const;private:charm_strName[100];intm_nAge;doublem_fScore;}; C語言使用下面語法初始化結(jié)構(gòu)變量:Rectangler={10,20.0};C++中不能使用這種方法,因?yàn)橐恍?shù)據(jù)組員可能不是公有組員。//錯(cuò)誤:不能在類作用//域外訪問非公有數(shù)據(jù)組員Studentstu={“aa”,10,90};為了防止破壞類封裝性,使用特殊組員函數(shù)來負(fù)責(zé)對(duì)象初始化。第3頁5.1結(jié)構(gòu)函數(shù)-關(guān)鍵點(diǎn)與類同名組員函數(shù)稱為結(jié)構(gòu)函數(shù)(Constructor,ctor),此函數(shù)在該類對(duì)象被創(chuàng)建時(shí)會(huì)被自動(dòng)調(diào)用,負(fù)責(zé)完成該對(duì)象初始化工作。結(jié)構(gòu)函數(shù)不能指定返回類型。每定義一個(gè)對(duì)象,該對(duì)象ctor被自動(dòng)調(diào)用。Students;此句背后動(dòng)作是首先為對(duì)象s分配內(nèi)存,然后調(diào)用ctor初始化對(duì)象。classStudent{public:Student();intGetAge()const;private:charm_strName[100];intm_nAge;doublem_fScore;}; Student::Student(){m_nAge=10;m_fScore=100;}第4頁5.1結(jié)構(gòu)函數(shù)-關(guān)鍵點(diǎn)結(jié)構(gòu)函數(shù)不能定義為const,不過能夠用來結(jié)構(gòu)常量對(duì)象,這是因?yàn)橹挥挟?dāng)結(jié)構(gòu)函數(shù)執(zhí)行完成后,對(duì)象常量性才能夠建立起來。Rectangle::Rectangle()const{}//錯(cuò)誤ctor定義對(duì)于常量對(duì)象只能調(diào)用常組員函數(shù)規(guī)則,結(jié)構(gòu)函數(shù)是個(gè)例外。假如一個(gè)類對(duì)象item是另一個(gè)類Container數(shù)據(jù)組員,則創(chuàng)建Container對(duì)象時(shí),會(huì)首先自動(dòng)為item調(diào)用結(jié)構(gòu)函數(shù)。換句話說,編譯器會(huì)自動(dòng)在Container結(jié)構(gòu)函數(shù)函數(shù)體前插入對(duì)item結(jié)構(gòu)函數(shù)調(diào)用。首先調(diào)用對(duì)象組員ctor,其次才是本身ctor。[演示]了解結(jié)構(gòu)函數(shù)調(diào)用時(shí)機(jī)第5頁5.2析構(gòu)函數(shù)-背景一個(gè)對(duì)象生存期結(jié)束(銷毀)時(shí)可能需要做些清理工作。打開文件需要關(guān)閉分配堆內(nèi)存需要釋放假如清理工作對(duì)應(yīng)函數(shù)能夠被自動(dòng)調(diào)用,就會(huì)降低程序員工作量,甚至犯錯(cuò)可能。能夠使用析構(gòu)函數(shù)(Destructor,dtor)自動(dòng)完成清理工作。第6頁5.2析構(gòu)函數(shù)-關(guān)鍵點(diǎn)析構(gòu)函數(shù)名必須為~加上類名。示例dtor是一類特殊組員函數(shù),它沒有參數(shù),不能重載,不能為其指定返回值。類中至多只有一個(gè)dtor。dtor在對(duì)象生存期即將結(jié)束時(shí)由系統(tǒng)自動(dòng)調(diào)用。析構(gòu)函數(shù)返回后,對(duì)象結(jié)束其生存期。假如沒有清理工作要做,則能夠不在類中定義析構(gòu)函數(shù)。【示例】析構(gòu)函數(shù)第7頁classStudent{public:Student();//ctor
~Student();//dtorintGetAge()const;private:charm_strName[100];intm_nAge;doublem_fScore;}; 第8頁5.2析構(gòu)函數(shù)-關(guān)鍵點(diǎn)dtor不能定義為常組員函數(shù),不過常量對(duì)象在析構(gòu)時(shí)候一樣會(huì)調(diào)用dtor。Rectangle::~Rectangle()const{}//錯(cuò)誤dtor定義對(duì)于常量對(duì)象只能調(diào)用常組員函數(shù)規(guī)則,dtor是個(gè)例外。假如類中包含組員對(duì)象,在執(zhí)行析構(gòu)函數(shù)時(shí)將首先執(zhí)行dtor函數(shù)體,然后為類中每個(gè)對(duì)象組員調(diào)用析構(gòu)函數(shù)。換句話說,編譯器會(huì)在類dtor函數(shù)體之后插入對(duì)類中每個(gè)組員對(duì)象dtor調(diào)用。對(duì)dtor調(diào)用次序恰好和對(duì)ctor調(diào)用次序相反。最先結(jié)構(gòu)對(duì)象最終被析構(gòu)。[演示]了解析構(gòu)函數(shù)調(diào)用時(shí)機(jī)第9頁classPerson{public:
Person(){m_strName=newchar[20];}//分配堆空間~Person(){delete[]m_strName;}//釋放堆空間voidSetName(constchar*name){strcpy(m_strName,name);}private:char*m_strName;}第10頁5.3結(jié)構(gòu)函數(shù)重載與dtor不一樣,ctor允許帶參而且能夠帶不一樣參數(shù),ctor允許重載。教材P273頁例子MFC中CString類定義在一個(gè)結(jié)構(gòu)函數(shù)中調(diào)用重載另一個(gè)結(jié)構(gòu)函數(shù)以簡化編程方法是錯(cuò)誤。因?yàn)榻Y(jié)構(gòu)函數(shù)只用于創(chuàng)建對(duì)象。這一點(diǎn)和普通重載函數(shù)不一樣。Tdate::Tdate(intm,intd,inty){….}Tdate::Tdate(intd){//下面語句只是創(chuàng)建//了另一個(gè)對(duì)象,而且//很快結(jié)束生存期。Tdate(4,d,1995);}專門定義一個(gè)組員函數(shù),然后全部結(jié)構(gòu)函數(shù)調(diào)用此組員函數(shù)即可。處理方法經(jīng)過給參數(shù)設(shè)置默認(rèn)值,能夠?qū)⒅剌d結(jié)構(gòu)函數(shù)合并為一個(gè)。示例第11頁classTdate{public:Tdate(intm=4,d=22,y=);private:intmonth;intday;intyear;};Tdate::Tdate(intm/*=4*/,intd/*=22*/,inty/*=*/){ month=m;day=d;year=y; cout<<month<<"/"<<day<<"/"<<year<<endl;}第12頁#include<iostream.h>classTdate{public:Tdate() {Init(4,15,1995);}Tdate(intd) {Init(4,d,1995);}Tdate(intm,intd) {Init(m,d,1995);}Tdate(intm,intd,inty) {Init(m,d,y);}
protected:intmonth;intday;intyear;
voidInit(intm,intd,inty){month=m;day=d;year=y;cout<<month<<"/"<<day<<"/"<<year<<endl;}};第13頁5.4默認(rèn)(缺省)結(jié)構(gòu)函數(shù)默認(rèn)結(jié)構(gòu)函數(shù)(dctor):不需要用戶指定實(shí)參就能被調(diào)用結(jié)構(gòu)函數(shù)。(教材上缺明確定義)Tdate::Tdate(){…}Rectangle::Rectangle(floatw=0.0,floath=0.0);假如沒有在類中定義任何ctor,則C++提供一個(gè)dctor,該dctor為無參結(jié)構(gòu)函數(shù),不作任何工作。類數(shù)據(jù)組員假如為簡單類型則不會(huì)被初始化,假如為其它類對(duì)象則自動(dòng)為其調(diào)用結(jié)構(gòu)函數(shù)。classStudent{private:charname[20];};等價(jià)于classStudent{public:Student(){}private:charname[20];};第14頁5.4默認(rèn)結(jié)構(gòu)函數(shù)-示例classStudent{public:Student(char*pName){strcpy(name,pName);}
Student(){name[0]=‘\0’;}private:charname[20];};voidmain(void){
//錯(cuò)誤:沒有匹配ctorStudents;}只要為類定義了一個(gè)帶參結(jié)構(gòu)函數(shù),C++就不再提供默認(rèn)結(jié)構(gòu)函數(shù),假如還需要無參結(jié)構(gòu)函數(shù),則必須顯式定義。第15頁5.5使用參數(shù)初始化對(duì)象Tdateadate;//調(diào)用默認(rèn)結(jié)構(gòu)函數(shù)(dctor)Tdatebdate(10);//OK,Tdate::Tdate(intd)等價(jià)于Tdatebdate=Tdate(10);Tdatecdate(3,12);//OK,Tdate::Tdate(intm,intd)等價(jià)于Tdatecdate=Tdate(3,12);Tdateddate();//此句沒有語法錯(cuò)誤
//Error:leftof'.GetYear'musthaveclass/struct/uniontypeintiy=ddate.GetYear();編譯器認(rèn)為ddate是個(gè)函數(shù)申明。所以使用dctor結(jié)構(gòu)對(duì)象時(shí),對(duì)象名后面不能跟()。為何Tdatebdate(10);不看作是函數(shù)申明?依據(jù)重載函數(shù)匹配標(biāo)準(zhǔn)來決定調(diào)用哪個(gè)結(jié)構(gòu)函數(shù)。第16頁補(bǔ)充:函數(shù)申明和對(duì)象定義判別Tdateaa;Tdateaa();Tdateaa(1);Tdateaa(z=1);Tdateaa(intz);Tdateaa(intz=1);判別上面形式是函數(shù)申明還是對(duì)象定義關(guān)鍵在于括號(hào)內(nèi)字符串能否被看作參數(shù)列表,假如能則一定是函數(shù)申明。第17頁5.6單參數(shù)結(jié)構(gòu)函數(shù)(1)單參數(shù)結(jié)構(gòu)函數(shù)是指只用一個(gè)參數(shù)即能夠調(diào)用結(jié)構(gòu)函數(shù)。能夠是只定義了一個(gè)參數(shù)結(jié)構(gòu)函數(shù),能夠是雖定義了多個(gè)參數(shù)但第一個(gè)參數(shù)以后全部參數(shù)都有缺省值ctor。當(dāng)使用帶一個(gè)參數(shù)ctor結(jié)構(gòu)對(duì)象時(shí),有三種等價(jià)寫法。最終一個(gè)寫法只適合用于單參數(shù)結(jié)構(gòu)函數(shù)。classRational//有理數(shù)類{public:Rational(intnumerator=0,intdenominator=1);…};Tdatedate(10);Tdatedate=Tdate(10);Tdatedate=10;Rationalr(2);Rationalr=Rational(2);Rationalr=2;等價(jià)等價(jià)第18頁5.6單參數(shù)結(jié)構(gòu)函數(shù)(2)缺省情況下,單參數(shù)結(jié)構(gòu)函數(shù)可用于類型轉(zhuǎn)換。重載函數(shù)匹配標(biāo)準(zhǔn):在嚴(yán)格匹配方式,經(jīng)內(nèi)部轉(zhuǎn)換后匹配方式都失敗后,將尋找經(jīng)過用戶定義轉(zhuǎn)換后參數(shù)匹配函數(shù)并調(diào)用。單參數(shù)結(jié)構(gòu)函數(shù)就是其中一個(gè)用戶定義轉(zhuǎn)換。當(dāng)同時(shí)存在各種可能轉(zhuǎn)換時(shí),重載函數(shù)匹配失敗,從而造成語法錯(cuò)誤。單參數(shù)結(jié)構(gòu)函數(shù)造成重載函數(shù)匹配失敗例子classA{public:A(char*);…};voidf(Aa);voidmain(){//OK,結(jié)構(gòu)A一個(gè)無//名對(duì)象,然后調(diào)用ff(“yes?”);}第19頁voidf(Bb){…}voidf(Aa){…}voidmain(){
//Error:Ambiguous,二義性//Callf(Aa)?orCallf(Ba)?f(“yes?”);}classA{public:A(char*);…};classB{public:B(char*);…};第20頁5.6單參數(shù)結(jié)構(gòu)函數(shù)(3)單參數(shù)ctor用于類型轉(zhuǎn)換時(shí)極有可能造成意外錯(cuò)誤。[演示]使用關(guān)鍵字explicit能夠抑制上述轉(zhuǎn)換行為。使用explicit關(guān)鍵字后,必須顯式調(diào)用結(jié)構(gòu)函數(shù)來初始化對(duì)象,也就是說不能再使用Tdatedate=10;這么結(jié)構(gòu)對(duì)象方式;不然將造成編譯錯(cuò)誤。classA{public:
explicitA(char*);…};voidf(Aa);voidmain(){Aa=“Hi”;//ERRORf(“yes?”);//ERROR}Aa=A(“Hi”);//OKf(A(“Yes?”));//OK第21頁教材P325錯(cuò)誤14.9第一段最終一句:“定義含一個(gè)參數(shù)結(jié)構(gòu)函數(shù)”應(yīng)為“定義單參數(shù)結(jié)構(gòu)函數(shù)”;倒數(shù)第二行“只會(huì)嘗試含一個(gè)參數(shù)結(jié)構(gòu)函數(shù)”應(yīng)為“只會(huì)嘗試單參數(shù)結(jié)構(gòu)函數(shù)”;voidfn(Student&s);此代碼不能經(jīng)過編譯,應(yīng)為voidfn(constStudent&s);不然會(huì)發(fā)生編譯錯(cuò)誤。第22頁5.7組員初始化列表-背景當(dāng)一個(gè)對(duì)象是另一個(gè)類組員時(shí):Point3daPoint;將自動(dòng)調(diào)用組員m_point2d默認(rèn)結(jié)構(gòu)函數(shù)。//二維平面一個(gè)點(diǎn)classPoint2d{public: Point2d(intx=0,inty=0){m_x=x;m_y=y;}private:intm_x;intm_y;};//三維空間一個(gè)點(diǎn)classPoint3d{public:Point3d(){m_z=0;}
private:Point2dm_point2d;intm_z;};第23頁5.7組員初始化列表-背景Point3dpoint(1,2,3);需要在Point3d結(jié)構(gòu)函數(shù)中調(diào)用Point2d非默認(rèn)結(jié)構(gòu)函數(shù),應(yīng)該怎么做?調(diào)用結(jié)構(gòu)函數(shù)不可行,因?yàn)閙_point2d已經(jīng)結(jié)構(gòu)過了。結(jié)構(gòu)一個(gè)無名對(duì)象,賦給m_point2d,可行不過效率低。【演示】在Point3d結(jié)構(gòu)函數(shù)中結(jié)構(gòu)了一個(gè)無名對(duì)象,賦給m_point2d,隨即將無名對(duì)象析構(gòu)。//三維空間一個(gè)點(diǎn)classPoint3d{public:Point3d(){m_z=0;} Point3d(intx,inty,intz){//錯(cuò)誤,結(jié)構(gòu)函數(shù)不能顯式調(diào)用m_point2d.Point2d(x,y);m_z=z;}private:Point2dm_point2d;intm_z;};//正確,不過效率低m_point2d=Point2d(x,y);第24頁5.7組員初始化列表應(yīng)使用組員初始化列表(memberinitializationlist)完成上述工作。Point3d::Point3d(intx,inty,intz):m_point2d(x,y),m_z(z){}組員初始化列表必須出現(xiàn)在結(jié)構(gòu)函數(shù)參數(shù)列表結(jié)束(右括號(hào))后和函數(shù)體之間,而且必須使用冒號(hào)。列表中對(duì)數(shù)據(jù)組員初始化只能使用括號(hào),不能使用等號(hào)。每個(gè)數(shù)據(jù)組員在初始化列表中最多只能出現(xiàn)一次。使用組員初始化列表方式將只調(diào)用一次Point2dctor。演示第25頁補(bǔ)充:賦值和初始化注意區(qū)分初始化和賦值:intaInt=10;//初始化intaInt(10);//初始化aInt=8;//賦值Point2dpoint(1,2);//初始化Point2dpoint=Point2d(1,2);//初始化point=Point2d(1,2);//賦值一旦進(jìn)入結(jié)構(gòu)函數(shù)函數(shù)體,對(duì)象結(jié)構(gòu)已經(jīng)確立,數(shù)據(jù)組員就已經(jīng)存在,在函數(shù)體中就只能進(jìn)行賦值操作。第26頁5.7組員初始化列表-使用下面四種情況只能使用組員初始化列表需要調(diào)用組員對(duì)象帶參結(jié)構(gòu)函數(shù)時(shí)。需要調(diào)用基類帶參結(jié)構(gòu)函數(shù)(后續(xù)章節(jié)講解)。需要初始化常量數(shù)據(jù)組員。需要初始化引用數(shù)據(jù)組員。推薦使用組員初始化列表來初始化類中每個(gè)組員,即使不是上述四種情況之一。Point2d::Point2d(intx=0,inty=0):m_x(x),m_y(y){}第27頁5.7組員初始化列表-常數(shù)據(jù)組員const修飾數(shù)據(jù)組員不能在類體中顯式初始化。//類體中以下代碼是錯(cuò)誤constfloatfMaxOverdraft=100.0;只能在結(jié)構(gòu)函數(shù)初始化列表中初始化。const修飾類數(shù)據(jù)組員能夠經(jīng)過常量、變量、函數(shù)返回值初始化。const修飾數(shù)據(jù)組員一但初始化就不能再修改,不論是在類體中還是類體外。const修飾數(shù)據(jù)組員在同一個(gè)類不一樣對(duì)象中能夠有不一樣值。//Credit.hclassCreditCard//信用卡{public:CreditCard(floate=100.0);…private://最大透支額度constfloatfMaxOverdraft;}//Credit.cpp#include<Credit.h>CreditCard::CreditCard(floata):fMaxOverdraft(a){}#include<Credit.h>CreditCardc1;CreditCardc2(1000.0);第28頁5.7組員初始化列表-初始化次序初始化次序并不是按照組員名在初始化列表中次序初始化;而是按照組員在類中申明次序初始化。初始化列表中數(shù)據(jù)組員總是在ctor函數(shù)體中組員賦值前被初始化。Point3d::Point3d(intx,inty,intz):m_z(z),m_point2d(x,y){}初始化次序?yàn)閙_point2d,m_zPoint3d::Point3d(intx,inty,intz):m_z(z){m_point2d=Point2d(x,y);}初始化次序?yàn)閙_point2d,m_z再對(duì)m_point2d賦值。第29頁5.7組員初始化列表-難于發(fā)覺錯(cuò)誤教材P287ch12_15.cpp例子。因?yàn)閚um先于age初始化,所以num值不正確。當(dāng)需要使用一個(gè)組員去初始化另一個(gè)組員時(shí),應(yīng)該將這么代碼放在ctor函數(shù)體中。查看修改后代碼第30頁classA{public:A(intj):age(j){
num=age+1;cout<<"age:"<<age<<endl;cout<<"num:"<<num<<endl;}protected:intnum;intage;};voidmain(){Asa(15);}classA{public:A(intj):age(j),num(age+1){cout<<"age:"<<age<<endl;cout<<"num:"<<num<<endl;}protected:intnum;intage;};voidmain(){Asa(15);}第31頁5.8拷貝結(jié)構(gòu)函數(shù)-背景對(duì)象作為函數(shù)參數(shù)傳遞時(shí),因?yàn)閰?shù)傳遞傳值語義,形參實(shí)際上是實(shí)參對(duì)象一個(gè)拷貝,換句話說形參對(duì)象是以實(shí)參對(duì)象為原本結(jié)構(gòu)出來一個(gè)新對(duì)象。有時(shí)候也需要用一個(gè)已經(jīng)有對(duì)象去結(jié)構(gòu)一個(gè)新對(duì)象。支持Undo類對(duì)象:在用戶對(duì)對(duì)象執(zhí)行修改之前,首先備份一個(gè)拷貝;當(dāng)用戶需要撤消對(duì)象修改時(shí)能夠使用備份對(duì)象恢復(fù)。第32頁5.8拷貝結(jié)構(gòu)函數(shù)-語法拷貝結(jié)構(gòu)函數(shù)申明語法:classname(classname&src);或者classname(constclassname&src);參數(shù)必須是引用,為何?拷貝結(jié)構(gòu)函數(shù)調(diào)用時(shí)機(jī):使用已經(jīng)有對(duì)象去初始化一個(gè)新對(duì)象時(shí)。Point2dp1(1,2);Point2dp2(p1);或者Point2dp2=p1;從函數(shù)中返回對(duì)象時(shí)。向函數(shù)傳遞對(duì)象時(shí)。第33頁5.8拷貝結(jié)構(gòu)函數(shù)-默認(rèn)行為假如沒有顯式定義拷貝結(jié)構(gòu)函數(shù),C++將為我們提供一個(gè)默認(rèn)拷貝結(jié)構(gòu)函數(shù)從而支持對(duì)象以拷貝方式初始化,對(duì)象拷貝方式和結(jié)構(gòu)變量一樣,都是按組員初始化(MemberwiseCopy)。假如一個(gè)類數(shù)據(jù)組員包含其它類對(duì)象,則首先對(duì)每個(gè)組員對(duì)象調(diào)用拷貝結(jié)構(gòu)函數(shù)或者默認(rèn)拷貝結(jié)構(gòu)函數(shù),然后再拷貝類中非對(duì)象組員?!狙菔尽縋318頁例子:了解調(diào)用時(shí)機(jī)實(shí)際上默認(rèn)拷貝結(jié)構(gòu)函數(shù)初始化方式能夠了解為將源對(duì)象占用內(nèi)存空間完整拷貝到目標(biāo)對(duì)象。Point2dp1(1,2);Point2dp2=p1;//或Point2dp2(p1);則p2.m_x為1,p2.m_y為2Point3dp1(1,2,3);Point3dp2=p1;//或Point3dp2(p1);則p2.m_x為1,p2.m_y為2,p2.m_z為3第34頁5.8拷貝結(jié)構(gòu)函數(shù)-默認(rèn)行為C++所提供默認(rèn)拷貝行為在一些情況下是不適當(dāng),甚至是錯(cuò)誤?!狙菔尽磕J(rèn)拷貝結(jié)構(gòu)函數(shù)帶來問題默認(rèn)拷貝行為只是拷貝每個(gè)組員,包含指向堆內(nèi)存指針,從而使得兩個(gè)對(duì)象指向了同一塊內(nèi)存;其中一個(gè)對(duì)象在析構(gòu)時(shí)釋放了該內(nèi)存,造成了另一個(gè)對(duì)象組員指針指向了無效內(nèi)存,成為野指針。第35頁5.8拷貝結(jié)構(gòu)函數(shù)-自定義拷貝為處理按組員初始化(淺拷貝)存在問題,能夠自定義拷貝結(jié)構(gòu)函數(shù)?!狙菔尽渴褂蒙羁截愄幚砩弦粋€(gè)演示問題當(dāng)我們需要拷貝行為和默認(rèn)行為不一樣時(shí)就需要定義拷貝結(jié)構(gòu)函數(shù)。默認(rèn)拷貝行為造成兩個(gè)對(duì)象擁有對(duì)同一個(gè)資源全部權(quán)時(shí),需要拷貝結(jié)構(gòu)函數(shù)。如某個(gè)類有一個(gè)組員,該組員應(yīng)該對(duì)每個(gè)對(duì)象都唯一。此時(shí)需要定義拷貝結(jié)構(gòu)函數(shù)通常假如類需要一個(gè)析構(gòu)函數(shù),則它也需要一個(gè)拷貝結(jié)構(gòu)函數(shù),因?yàn)橐粋€(gè)自定義析構(gòu)函數(shù)意味著額外資源需要在析構(gòu)之前被釋放。類Point3d是否需要我們編寫自定義拷貝結(jié)構(gòu)函數(shù)?第36頁P(yáng)oint3d類定義//二維平面一個(gè)點(diǎn)classPoint2d{public: Point2d(intx=0,inty=0):m_x(x),m_y(y){}private:intm_x;intm_y;};//三維空間一個(gè)點(diǎn)classPoint3d{public:Point3d(intx=0,inty=0,intz=0):m_point2d(x,y),m_z(z){}private:Point2dm_point2d;intm_z;};第37頁5.8拷貝結(jié)構(gòu)函數(shù)-調(diào)用一但自定義了拷貝結(jié)構(gòu)函數(shù),則類及其組員對(duì)象拷貝結(jié)構(gòu)工作全部由自定義拷貝ctor負(fù)責(zé)。示例當(dāng)需要調(diào)用某個(gè)類拷貝結(jié)構(gòu)函數(shù)時(shí)(用已經(jīng)有對(duì)象初始化一個(gè)新對(duì)象時(shí),從函數(shù)中返回對(duì)象時(shí),以傳值方式向函數(shù)傳遞對(duì)象時(shí)):假如對(duì)象所屬類顯式?jīng)]有定義拷貝結(jié)構(gòu)函數(shù),則執(zhí)行默認(rèn)拷貝結(jié)構(gòu)函數(shù)(按組員初始化)。假如對(duì)象所屬類顯式定義了拷貝結(jié)構(gòu)函數(shù):假如拷貝結(jié)構(gòu)函數(shù)是可訪問,就去調(diào)用它假如拷貝結(jié)構(gòu)函數(shù)是不可訪問,就產(chǎn)生編譯錯(cuò)誤??衫眠@一點(diǎn)使得類不允許拷貝結(jié)構(gòu)。示例第38頁classA{public:A(){…}
A(constA&){…}…};classB{public:B(){…}
B(constB&b){…}private:Am_a;};voidmain(){Bb1;//為B生成默認(rèn)拷貝結(jié)構(gòu)函數(shù),將調(diào)用A::A(constA&)Bb2=b1;}//將不會(huì)調(diào)用A::A(constA&),而只是調(diào)用B::B(constB&)B(constB&b):m_a(b.m_a){…}//將首先調(diào)用A::A(constA&),然后調(diào)用B::B(constB&)第39頁classA{public:A(){…}private:
//只是申明此函數(shù),并不定義此函數(shù)。//使用了C++中延遲錯(cuò)誤檢驗(yàn)特征,即只有當(dāng)一個(gè)函數(shù)//在程序中被調(diào)用了,編譯器才會(huì)去檢驗(yàn)函數(shù)定義是否//存在。
A(constA&);…};…Aa;//errorC2248:'A::A':cannotaccessprivatememberdeclaredinclass'A'Ab(a);第40頁5.9示例P326習(xí)題14.23個(gè)印刷錯(cuò)誤for(inti=0;i<size;i++)cout<<buffer[j]<<endl;buffer[j]=j+1;拷貝結(jié)構(gòu)實(shí)現(xiàn)為:Vector::Vector(constVector&v) :size(v.size){buffer=newint[size];for(inti=0;i<size;i++)buffer[i]=v.buffer[i];}Vector::Vector(constVector&v) :size(v.size){buffer=newint[size];memcpy(buffer,v.buffer, size*sizeof(int));}第41頁5.9示例使用結(jié)構(gòu)函數(shù)和析構(gòu)函數(shù)來完成第四章中類LinkListInitialize函數(shù)和Destroy函數(shù)所完成功效,并編寫拷貝結(jié)構(gòu)函數(shù)實(shí)現(xiàn)鏈表類深拷貝。演示使用結(jié)構(gòu)函數(shù)和析構(gòu)函數(shù)重寫第四章中FileWrapper類。為了預(yù)防FileWrapper兩個(gè)對(duì)象引用到同一份打開文件上,將拷貝結(jié)構(gòu)函數(shù)申明為私有。演示第42頁5.10再看new和deletemalloc和free無能為力地方:void*malloc(size_tsize);voidfree(void*memblock);上述兩個(gè)函數(shù)原型沒有包含類型信息,所以在為對(duì)象分配內(nèi)存時(shí)無法自動(dòng)調(diào)用結(jié)構(gòu)函數(shù),在釋放對(duì)象占用內(nèi)存時(shí)無法自動(dòng)調(diào)用析構(gòu)函數(shù)。new和delete用于處理上述問題。在使用new分配內(nèi)存時(shí)提供了類型信息,實(shí)現(xiàn)計(jì)算類型大小,分配對(duì)應(yīng)數(shù)量堆內(nèi)存,然后依據(jù)類名自動(dòng)調(diào)用結(jié)構(gòu)函數(shù)。在使用delete釋放內(nèi)存時(shí),首先依據(jù)指針類型信息自動(dòng)調(diào)用析構(gòu)函數(shù),然后釋放內(nèi)存。第43頁5.10再看new和delete使用new為創(chuàng)建一個(gè)對(duì)象時(shí),能夠在類名后跟參數(shù),new依據(jù)參數(shù)匹配標(biāo)準(zhǔn)調(diào)用結(jié)構(gòu)函數(shù);假如沒有跟參數(shù),則調(diào)用默認(rèn)結(jié)構(gòu)函數(shù)。Point2d*p=newPoint2d; deletep;Point2d*p=newPoint2d(); deletep;Point2d*p=newPoint2d(1,2); deletep;Point2d*p2=newPoint2d(*p); deletep2;在堆上分配對(duì)象數(shù)組時(shí),不能提供參數(shù),所以只能調(diào)用類默認(rèn)ctor。假如該類沒有定義默認(rèn)結(jié)構(gòu)函數(shù),則不能分配這類對(duì)象數(shù)組。在堆上分配對(duì)象數(shù)組必須用delete[]釋放。演示Point2d*p=newPoint2d[10];delete[]p;第44頁5.10示例P326習(xí)題14.1#include<iostream.h>classSamp{public:voidSetij(inta,intb){i=a,j=b;}
~Samp(){cout<<"Destroying.."<<i<<endl;}
intGetMulti(){returni*j;}protected:inti;intj;};voidmain(){Samp*p=newSamp[10];if(!p){cout<<"Allocationerror\n";return;}
for(intj=0;j<10;j++)p[j].Setij(j,j);for(intk=0;k<10;k++){cout<<"Multi["<<k<<"]is:"<<p[k].GetMulti()<<endl;delete[]p;}第45頁5.11對(duì)象結(jié)構(gòu)次序局部自動(dòng)對(duì)象在塊(局部)作用域內(nèi)按照定義次序結(jié)構(gòu)并逆序析構(gòu)。在局部作用域中最早結(jié)構(gòu)對(duì)象最遲析構(gòu)。局部靜態(tài)對(duì)象在第一次被使用時(shí)結(jié)構(gòu),而且在程序退出時(shí)析構(gòu)。全部全局對(duì)象在主函數(shù)main之前都將結(jié)構(gòu)完成。假如結(jié)構(gòu)全局對(duì)象時(shí)發(fā)生了錯(cuò)誤或者死循環(huán),main函數(shù)將得不到控制權(quán)。全局(靜態(tài)或者非靜態(tài))對(duì)象在文件作用域中按照定義次序結(jié)構(gòu)。不一樣文件作用域中全局對(duì)象結(jié)構(gòu)次序不定。不應(yīng)該在一個(gè)全局對(duì)象中使用另一個(gè)全局對(duì)象來初始化對(duì)象組員按其在所屬類中申明次序結(jié)構(gòu)并逆序析構(gòu)?!狙菔尽坎灰粯幼饔糜?qū)ο蠼Y(jié)構(gòu)次序第46頁5.12暫時(shí)對(duì)象當(dāng)函數(shù)返回一個(gè)對(duì)象時(shí),要?jiǎng)?chuàng)建一個(gè)暫時(shí)變量以存放返回值。是否使用暫時(shí)對(duì)象是由編譯器來決定,C++標(biāo)準(zhǔn)中并沒有明確要求什么時(shí)候一定要使用暫時(shí)變量。教材P323例子將這個(gè)例子main函數(shù)中代碼修改為 Students=fn();//初始化,不是
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 條形碼、電子標(biāo)簽等物聯(lián)網(wǎng)技術(shù)在文檔管理中的應(yīng)用
- 2025年福建省職教高考《職測(cè)》核心考點(diǎn)必刷必練試題庫(含答案)
- 2025年楊凌職業(yè)技術(shù)學(xué)院高職單招語文2018-2024歷年參考題庫頻考點(diǎn)含答案解析
- 中國銀行個(gè)人借款合同
- 正規(guī)的借款合同范本
- 航空運(yùn)輸人才培養(yǎng)與行業(yè)發(fā)展
- 事業(yè)單位的試用期勞動(dòng)合同范本
- 鋼筋單項(xiàng)勞務(wù)承包合同
- 臨設(shè)建設(shè)工程施工勞務(wù)分包合同
- 消防產(chǎn)品的買賣合同
- (二模)遵義市2025屆高三年級(jí)第二次適應(yīng)性考試試卷 地理試卷(含答案)
- 二零二五隱名股東合作協(xié)議書及公司股權(quán)代持及回購協(xié)議
- IQC培訓(xùn)課件教學(xué)課件
- 2025年計(jì)算機(jī)二級(jí)WPS考試題目
- 高管績效考核全案
- 2024年上海市中考英語試題和答案
- 教育部《中小學(xué)校園食品安全和膳食經(jīng)費(fèi)管理工作指引》知識(shí)培訓(xùn)
- 長沙醫(yī)學(xué)院《無機(jī)化學(xué)》2021-2022學(xué)年第一學(xué)期期末試卷
- eras婦科腫瘤圍手術(shù)期管理指南解讀
- 初一到初三英語單詞表2182個(gè)帶音標(biāo)打印版
- 《人力資源管理》全套教學(xué)課件
評(píng)論
0/150
提交評(píng)論