版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
C++程序設(shè)計教程(第二版)第九章對象生滅7/27/20231C++程序設(shè)計教程(第二版)第九章對象生滅7/27/20第九章內(nèi)容構(gòu)造函數(shù)設(shè)計構(gòu)造函數(shù)的重載類成員初始化構(gòu)造順序拷貝構(gòu)造函數(shù)析構(gòu)函數(shù)對象轉(zhuǎn)型與賦值7/27/20232第九章內(nèi)容構(gòu)造函數(shù)設(shè)計7/27/202321.構(gòu)造函數(shù)設(shè)計
初始化要求定義一個對象,其形式與定義一個變量相似,但更具意義。對象與變量的不同在于對象對應(yīng)于事物,要求從誕生之時起便有明確的意義.對象必須建立一種初始化機(jī)制,以滿足在編程中可以針對實(shí)際問題所提出的要求而賦給一個有意義的初值。創(chuàng)建一個對象,若創(chuàng)建的是全局對象,則以全0的模式表示對象,若創(chuàng)建局部對象,則以隨機(jī)值表示對象。7/27/202331.構(gòu)造函數(shù)設(shè)計
初始化要求定義一個對象,對象的初始化不是簡單的參數(shù)與成員對應(yīng),而是聯(lián)系參數(shù)到成員的過程.封裝性要求StructPoint{intx,y;};Pointd={2,3};classPoint{intx,y;//…};Pointd={2,3};正確錯誤封裝性的要求杜絕了這種初始化形式,事實(shí)上,這種形式根本不能完成對象的初始化過程中的校驗(yàn)和計算工作。對象通常是一個復(fù)雜的實(shí)體,在構(gòu)建對象過程中,并不一定是一個初值對應(yīng)一個對象分量。許多時候,一個初值只是傳遞一個信息,告訴對象的創(chuàng)建工作應(yīng)怎么進(jìn)行。封裝性要求對象創(chuàng)建中按傳遞的信息進(jìn)行一個過程化的初始化工作。7/27/20234對象的初始化不是簡單的參數(shù)與成員對應(yīng),而是聯(lián)系函數(shù)形式構(gòu)造函數(shù)(constructor)是與類名同名的特殊的成員函數(shù),當(dāng)定義該類的對象時,構(gòu)造函數(shù)將被自動調(diào)用以實(shí)現(xiàn)對該對象的初始化。構(gòu)造函數(shù)不能有返回值,因而不能指定包括void在內(nèi)的任何返回值類型。構(gòu)造函數(shù)的定義體可與其它成員函數(shù)成員一樣,放在類內(nèi)或類外都可。構(gòu)造函數(shù)的定義格式為:類名(形參說明){函數(shù)體}構(gòu)造函數(shù)既可定義成有參函數(shù),也可義成無參函數(shù),要根據(jù)問題的需要來定。全局變量和靜態(tài)變量在定義時,將自動賦初值為0;局部變量在定義時,其初始值不固定的。而當(dāng)對象被定義時,由于對象的意義表達(dá)了現(xiàn)實(shí)世界的實(shí)體,所以一旦定義對象,就必須有一個有意義的初始值,在C++中,在定義對象的同時,給該對象初始化的方法就是利用構(gòu)造函數(shù)。7/27/20235函數(shù)形式構(gòu)造函數(shù)(constructor)是與類名同名的特殊例:類person包括4個數(shù)據(jù)成員,用來記錄人員信息。生成對象obj,并使用構(gòu)造函數(shù)為obj賦予初始值。#include<windows.h>#include<iostream.h>classPerson //定義類{private: //類Person的數(shù)據(jù)成員charname[10]; //姓名intage; //年齡intsalary; //薪金chartel[8]; //電話public: //構(gòu)造函數(shù)PersonPerson(char*xname,intxage,intxsalary,char*xtel);voiddisp();};//函數(shù)Person的定義Person::Person(char*xname,intxage,intxsalary,char*xtel){strcpy(name,xname);//給各數(shù)據(jù)成員提供初值age=xage;salary=xsalary;strcpy(tel,xtel);}7/27/20236例:類person包括4個數(shù)據(jù)成員,用來記錄人員//函數(shù)disp的定義voidPerson::disp(){cout<<endl;cout<<"姓名:"<<name<<endl;cout<<"年齡:"<<age<<endl;cout<<"工資:"<<salary<<endl;cout<<"電話:"<<tel<<endl<<endl;}//主函數(shù)voidmain(){//生成對象obj并初始化Personobj("張立三",25,850,"45672314");//顯示objobj.disp();}7/27/20237//函數(shù)disp的定義7/27/20237程序的執(zhí)行結(jié)果是:姓名:張立三年齡:25工資:850電話:45672314在主函數(shù)中的Personobj("張立三",25,850,"45672314");中完成了以下幾個功能:1.定義并生成了對象obj。2.在生成對象obj的同時,自動調(diào)用相應(yīng)類的構(gòu)造函數(shù)Person3.將初始值"張立三",25,850,"45672314"傳遞給構(gòu)造函數(shù)Person相應(yīng)的形參xname,xage,xsalary,xtel。4.執(zhí)行構(gòu)造函數(shù)體,將相應(yīng)的值賦給相應(yīng)的數(shù)據(jù)成員。7/27/20238程序的執(zhí)行結(jié)果是:7/27/20238一次性對象創(chuàng)建對象時如果不給出對象名,直接以類名調(diào)用構(gòu)造函數(shù),則產(chǎn)生一個無名對象。無名對象經(jīng)常在參數(shù)傳遞時使用。例如:cout<<Date(2003,12,23);Date(2003,12,23)是一個對象,該對象在做了<<操作后便煙消云散了,所以這種對象一般用在創(chuàng)建后不需要反復(fù)使用的場合。7/27/20239一次性對象創(chuàng)建對象時如果不給出對象名,直接以
2.構(gòu)造函數(shù)重載
構(gòu)造函數(shù)畢竟是函數(shù),是函數(shù)就可以重載。不但可以重載,還可以設(shè)置默認(rèn)參數(shù)。如果一個類中出現(xiàn)了兩個以上的同名的成員函數(shù)時,稱為類的成員函數(shù)的重載。classDate{public:Date(conststring&s);//重載Date(inty=2003,intm=12,intd=1);//參數(shù)默認(rèn)//...};intmain(){Dated(“2006-12-26”);Datee(2000,12,25);Datef(2001,10);Dateg(2002);Dateh;//...}7/27/202310
2.構(gòu)造函數(shù)重載
構(gòu)造函數(shù)畢竟是函數(shù),是函Dateh;這行代碼似乎是一個錯誤,對于對象的創(chuàng)建,即對于無參的構(gòu)造函數(shù)的調(diào)用,應(yīng)該是g(),加上類名,即寫成:Dateg();但是,從語法上來講,這個語句也是名叫g(shù)的返回臨時Date對象的函數(shù)聲明!因此,C++語言在設(shè)計時,為了區(qū)別無初始化的對象定義和返回類對象的無參函數(shù)聲明的差別,也為了保持無初始化變量定義與無初始化(無參)對象定義的一致性,規(guī)定無參對象定義語句為:inta;//變量定義intb;//返回整型值的無參函數(shù)聲明Dateg;//無參對象定義,加空括號后就成了無參函數(shù)聲明Dateg();//返回類對象的無參函數(shù)聲明7/27/202311Dateh;這行代碼似乎是一個錯誤,對于對象的創(chuàng)建,即對對于返回對象值的有參函數(shù)聲明和有初始化的對象定義語句,由于函數(shù)聲明中的參數(shù)有類型引導(dǎo),而對象定義的初始化中無類型引導(dǎo),它們本身(或在編譯器看來)是可以區(qū)分的:Datee(2002);//對象定義Datee(inty);//函數(shù)聲明7/27/202312對于返回對象值的有參函數(shù)聲明和有初始化的對象C++規(guī)定,每個類必須有一個構(gòu)造函數(shù)。如果在類中沒有顯式定義構(gòu)造函數(shù)時,則C++編譯系統(tǒng)在編譯時為該類提供一個默認(rèn)的構(gòu)造函數(shù),該默認(rèn)構(gòu)造函數(shù)是個無參函數(shù),它僅負(fù)責(zé)創(chuàng)建對象,而不做任何初始化工作。classDate{public://相當(dāng)于定義了Date(){}};intmain(){Dated;//ok//...}與變量定義相似,在用默認(rèn)構(gòu)造函數(shù)創(chuàng)建對象時,如果創(chuàng)建的是全局對象或靜態(tài)對象,則對象的默認(rèn)值為0,否則對象的初始值是不定的。7/27/202313C++規(guī)定,每個類必須有一個構(gòu)造函數(shù)。如果在類中沒有顯式定只要一個類定義了一個構(gòu)造函數(shù)(不一定是無參構(gòu)造函數(shù)),C++編譯系統(tǒng)就不再提供默認(rèn)的構(gòu)造函數(shù)。任何其他的構(gòu)造函數(shù)定義,都將阻止默認(rèn)無參空函數(shù)的產(chǎn)生:classDate{public:Date(inty,intm,intd){}//...};intmain(){Dated;//error//...}7/27/202314只要一個類定義了一個構(gòu)造函數(shù)(不一定是無參構(gòu)造函數(shù)),7/2當(dāng)構(gòu)造函數(shù)有缺省參數(shù)時,稱為具有缺省參數(shù)的構(gòu)造函數(shù),在使用時要防止二義性。如:classMyclass//定義類Myclass{private:intmember;public:Myclass();Myclass(inti);……}Myclass:Myclass()//構(gòu)造函數(shù)Myclass{member=10;}7/27/202315當(dāng)構(gòu)造函數(shù)有缺省參數(shù)時,稱為具有缺省參數(shù)的構(gòu)Myclass:Myclass(inti=10)//構(gòu)造函數(shù)Myclass(inti),該函數(shù)//的形參i為缺省參數(shù){member=i;}voidmain(){Myclassx(20);Myclassy; //產(chǎn)生二義性,無法確定自動調(diào)用哪個構(gòu)造//函數(shù)完成對象的構(gòu)造……}7/27/202316Myclass:Myclass(inti=10)//構(gòu)造回顧:上節(jié)課主要講了構(gòu)造函數(shù)的概念、意義及定義方式、構(gòu)造函數(shù)的重載。7/27/202317回顧:7/27/202317
3.類成員初始化
默認(rèn)調(diào)用的無參構(gòu)造函數(shù)在類定義中有數(shù)據(jù)成員和成員函數(shù),數(shù)據(jù)成員可以是內(nèi)部數(shù)據(jù)類型的變量實(shí)體,也可以是對象實(shí)體。如果一個類A的對象作為另一個類B的數(shù)據(jù)成員,則在類B的對象創(chuàng)建過程中,調(diào)用其構(gòu)造函數(shù)的過程中,數(shù)據(jù)成員(類A的對象)會自動調(diào)用類A的構(gòu)造函數(shù)。這樣就會面臨一些問題。例:有一個學(xué)號類和一個學(xué)生類,學(xué)生類中包含了學(xué)號類的對象,因此在構(gòu)造學(xué)生類對象時,面臨著學(xué)號類對象的構(gòu)造。7/27/202318
3.類成員初始化
默認(rèn)調(diào)用的無參構(gòu)造函數(shù)classStudentID{intvalue;public:
StudentID(){staticintnextStudentID=0;value=++nextStudentID;cout<<"Assigningstudentid"<<value<<"\n";}};//-----------------------------------classStudent{stringname;
StudentIDid;public:Student(stringn="noName"){cout<<"Constructingstudent"+n+"\n";name=n;}};//-----------------------------------intmain(){Students("Randy");}//==============================在學(xué)生類的構(gòu)造函數(shù)中并沒有看到學(xué)號類對象初始化的痕跡,而數(shù)據(jù)成員name倒被賦了初值。從運(yùn)行的結(jié)果看,當(dāng)學(xué)生類對象被構(gòu)造時,一個學(xué)號對象也創(chuàng)建了,而且學(xué)號類的構(gòu)造函數(shù)先于學(xué)生類對象的構(gòu)造函數(shù)體的執(zhí)行而執(zhí)行。7/27/202319classStudentID{在學(xué)生類的構(gòu)對于Students(“Randy”);其內(nèi)部的執(zhí)行順序是這樣的:(1)先分配學(xué)生類對象s的空間,調(diào)用Student構(gòu)造函數(shù);(2)在Student構(gòu)造函數(shù)體尚未執(zhí)行時,由于看到了類的對象成員ID,轉(zhuǎn)而去調(diào)用學(xué)號類的無參構(gòu)造函數(shù);相當(dāng)于執(zhí)行定義語句:StudentIDid;(3)執(zhí)行了學(xué)號類構(gòu)造函數(shù)體,輸出結(jié)果的第1行信息,返回到Student構(gòu)造函數(shù);(4)執(zhí)行Student構(gòu)造函數(shù)體,輸出結(jié)果的第2行信息,完成全部構(gòu)造工作。說明:先成員構(gòu)造,后自身構(gòu)造.成員構(gòu)造不見顯式調(diào)用,而是悄悄調(diào)用無參構(gòu)造函數(shù).對學(xué)號類構(gòu)造函數(shù)的調(diào)用時默認(rèn)的,默認(rèn)調(diào)用便是調(diào)用無參構(gòu)造函數(shù),而正好學(xué)號類設(shè)計的構(gòu)造函數(shù)就是無參構(gòu)造函數(shù)。7/27/202320對于Students(“Randy”);其內(nèi)部的執(zhí)行順序初始化的困惑在剛剛的實(shí)例中,只是初始化了名稱,而沒有給定學(xué)號。如果,在學(xué)生對象創(chuàng)建中,既要初始化名稱,又要給定一個指定的初始化學(xué)號,也就是不要默認(rèn)調(diào)用無參構(gòu)造函數(shù),那么類該如何操作呢?如果不能在創(chuàng)建StudentID的過程中初始化對象,就不能將對象值設(shè)置到位。下面給出一個不正確的初始化嘗試,還是對剛才的例子作修改:7/27/202321初始化的困惑在剛剛的實(shí)例中,只是初始化了名稱classStudentID{intvalue;public:
StudentID(intid=0){value=id;cout<<"Assigningstudentid"<<value<<"\n";}};//-----------------------------------classStudent{stringname;StudentIDid;public:Student(stringn="noName",intssID=0){cout<<"Constructingstudent"+n+"\n";name=n;
StudentIDid(ssID);}};//-----------------------------------intmain(){Students("Randy",58);}//====================================運(yùn)行結(jié)果:7/27/202322classStudentID{運(yùn)行結(jié)果:7/27/2023S對象初始化的學(xué)號為58,重新設(shè)計了Student構(gòu)造函數(shù),將該值傳遞給了它,所以形參ssID的值也為58。但是我們看到轉(zhuǎn)而調(diào)用的StudentID構(gòu)造函數(shù)執(zhí)行體卻沒有輸出58,而是默認(rèn)的0學(xué)號。這說明轉(zhuǎn)而調(diào)用的仍然是無參構(gòu)造函數(shù)。將StudentID的構(gòu)造函數(shù)寫成參數(shù)默認(rèn)是為了讓無參構(gòu)造函數(shù)調(diào)用也能通過,以便讓整個程序順利運(yùn)行。乃至后來,要想在Student類內(nèi),通過構(gòu)造函數(shù)體中的對象初始化創(chuàng)建的定義語句來改變id的值,發(fā)現(xiàn)這僅僅只是區(qū)別于s對象中的id對象的一個局部對象,等到構(gòu)造函數(shù)結(jié)束時,該局部對象的局部生命期到期而不銷毀。7/27/202323S對象初始化的學(xué)號為58,重新設(shè)計了St如果一個類A的對象作為另一個類B的數(shù)據(jù)成員,則在類B的對象創(chuàng)建過程中,調(diào)用其構(gòu)造函數(shù)的過程中,數(shù)據(jù)成員(類A的對象)會自動調(diào)用類A的構(gòu)造函數(shù)。
如果類A的構(gòu)造函數(shù)為有參函數(shù)時,則在程序中必須在類B的構(gòu)造函數(shù)的括號后面加一“:”和被調(diào)用的類A的構(gòu)造函數(shù),且調(diào)用類A的構(gòu)造函數(shù)時的實(shí)參值必須來自類B的形參表中的形參。這種方法稱為初始化表的方式調(diào)用構(gòu)造函數(shù)。
這種在構(gòu)造函數(shù)的參數(shù)列表的右括號后面,花括號前面,用冒號引出構(gòu)造函數(shù)的調(diào)用表,可以省略類型名稱,但卻行創(chuàng)建對象之職。初始化表調(diào)用構(gòu)造函數(shù)7/27/202324如果一個類A的對象作為另一個類B的數(shù)據(jù)成員,則類X的構(gòu)造函數(shù)的定義格式應(yīng)為:X::X(參數(shù)表0):成員1(參數(shù)表1),成員2(參數(shù)表2),…,成員n(參數(shù)表n){……}其中,參數(shù)表1提供初始化成員1所需的參數(shù),參數(shù)表2提供初始化成員2所需的參數(shù),依此類推。并且這幾個參數(shù)表的中的參數(shù)均來自參數(shù)表0,另外,初始化X的非對象成員所需的參數(shù),也由參數(shù)表0提供。在構(gòu)造新類的對象過程中,系統(tǒng)首先調(diào)用其子對象的構(gòu)造函數(shù),初始化子對象;然后才執(zhí)行類X自己的構(gòu)造函數(shù),初始化類中的非對象成員。對于同一類中的不同子對象,系統(tǒng)按照它們在類中的說明順序調(diào)用相應(yīng)的構(gòu)造函數(shù)進(jìn)行初始化,而不是按照初始化表的順序。7/27/202325類X的構(gòu)造函數(shù)的定義格式應(yīng)為:7/27/202例:#include<iostream>usingnamespacestd;//-------------------------------------classStudentID{intvalue;public:
StudentID(intid=0)//有參構(gòu)造函數(shù){value=id;cout<<"Assigningstudentid"<<value<<endl;}};//-----------------------------------對剛才的例子進(jìn)行改進(jìn)7/27/202326例:#include<iostream>對剛才的例子進(jìn)行改進(jìn)classStudent{stringname;StudentIDid;public:Student(stringn="noname",intssID=0):id(ssID),name(n){cout<<"Constructingstudent"<<n<<"\n";}};//-----------------------------------intmain(){Students("Randy",98);Studentt("Jenny");}//==========================7/27/202327classStudent{7/27/202327
4.構(gòu)造順序
在程序中,各種作用域的對象很多,有些對象還包含在別的對象里面,有些對象早在main函數(shù)開始運(yùn)行之前就已經(jīng)建立了。創(chuàng)建對象的惟一途徑是調(diào)用構(gòu)造函數(shù)。構(gòu)造函數(shù)時一段程序,所以構(gòu)造對象的先后順序不同,直接影響程序執(zhí)行的先后順序,導(dǎo)致不同的運(yùn)行結(jié)果。C++給構(gòu)造對象的順序做了專門的規(guī)定。局部對象局部和靜態(tài)對象是指塊作用域(局部作用域)和文件作用域的對象。它們的聲明順序與它們在程序中出現(xiàn)的順序是一致的。見課本307頁例9.87/27/202328
4.構(gòu)造順序
在程序中,各種作用域的對象在C中,所有的局部變量(沒有對象)都是在函數(shù)開始執(zhí)行時統(tǒng)一創(chuàng)建的,創(chuàng)建的順序是根據(jù)變量在程序中按語句行出現(xiàn)的順序。而C++卻不同,它是根據(jù)運(yùn)行中定義對象的順序來決定對象創(chuàng)建的順序。而且,靜態(tài)對象只創(chuàng)建一次。全局對象和全局變量一樣,所有全局對象在主函數(shù)啟動之前,全部已近被構(gòu)造。因?yàn)闃?gòu)造過程是程序語句的執(zhí)行過程,所以,可以想象在程序啟動之前,已經(jīng)有程序語句(構(gòu)造函數(shù))在那里被執(zhí)行過了。7/27/202329在C中,所有的局部變量(沒有對象)都是在函數(shù)開同一工程不同代碼文件全局對象的創(chuàng)建沒有明確順序規(guī)定.對策:不要讓不同文件的全局對象互為依賴.因?yàn)橐蕾嚲哂邢群笮裕淙謱ο蟮膭?chuàng)建不能保證該依賴性發(fā)揮作用.全局對象在main函數(shù)啟動之前生成,而調(diào)試則在main函數(shù)啟動之后.對策:調(diào)試時,應(yīng)先將全局對象作為局部對象來運(yùn)行觀察.或者,在構(gòu)造函數(shù)中添加輸出語句來觀察運(yùn)行過程.7/27/202330同一工程不同代碼文件全局對象的創(chuàng)建沒有明確順序規(guī)定.7/27成員對象的構(gòu)造順序按類定義的出現(xiàn)順序成員對象classA{public:A(intx){cout<<"A:"<<x<<"->";}};//-----------------------------------classB{public:B(intx){cout<<"B:"<<x<<"->";}};//-----------------------------------classC{Aa;Bb;public:C(intx,inty):b(x),a(y){cout<<"C\n";}};//-----------------------------------intmain(){Cc(15,9);}//============================classC按A、B的順序定義對象成員,其構(gòu)造函數(shù)又按b、a的順序進(jìn)行構(gòu)造。到底聽誰的,以定義順序說了算。7/27/202331成員對象的構(gòu)造順序按類定義的出現(xiàn)順序成員對象classA{構(gòu)造位置全局?jǐn)?shù)據(jù)區(qū):全局對象,靜態(tài)全局對象,靜態(tài)局部對象,常對象類的靜態(tài)數(shù)據(jù)成員也存放在該數(shù)據(jù)區(qū)。目的是為了讓對象的生命周期與運(yùn)行的程序等壽命。棧區(qū):局部對象在函數(shù)中定義好、局部對象,隨著被調(diào)用的返回而析構(gòu)(銷毀)。動態(tài)存儲區(qū)(也稱堆區(qū)):用new申請的對象用delete銷毀。特殊地址空間除此之外,還可以指定特殊地址空間,存放對象7/27/202332構(gòu)造位置全局?jǐn)?shù)據(jù)區(qū):7/27/202332回顧7/27/202333回顧7/27/202333
5.拷貝構(gòu)造函數(shù)對象本體與對象實(shí)體:對象本體也是對象主體,對象實(shí)體則還包括屬于對象的衍生物,如,某個人體是人類對象的主體,然而某人還擁有父母,房產(chǎn)等屬于某人的世系或資產(chǎn),描述人的屬性不僅僅只是人體數(shù)據(jù).從形式上看,對象除了包括數(shù)據(jù)成員,還包括指向數(shù)據(jù)的指針.對象本體與對象實(shí)體是不一致就是說有時我們會需要把a(bǔ)對象的屬性全部轉(zhuǎn)給b對象,
對象本體與對象實(shí)體一致就是你要將a對象的屬性賦給a對象本身。7/27/202334
5.拷貝構(gòu)造函數(shù)對象本體與對象實(shí)體:7/27/20233對于一個簡單的變量的初始化方法是用一個常量或變量初始化另一個變量,例如:doublex=12.36;doubley=x;疑問:前面介紹了用構(gòu)造函數(shù)初始化對象,那么能不能像簡單變量的初始化一樣,直接用一個對象來初始化另一個對象呢?答案是肯定的。例:以定義的一個Point類為例,說明用一個對象來初始化另一個對象。Pointpt1(10,20);Pointpt2=pt1;那么,后一句也可寫成Pointpt2(pt1);它是用pt1初始化pt2,此時,pt2各個成員的值與pt1各個成員的值相同,也就是說,pt1各個成員的值被復(fù)制到pt2相應(yīng)的成員當(dāng)中。在這個初始化過程當(dāng)中,實(shí)際上調(diào)用了一個拷貝構(gòu)造函數(shù)。7/27/202335對于一個簡單的變量的初始化方法是用一個常量或變量初始化另一個拷貝構(gòu)造函數(shù):拷貝構(gòu)造函數(shù)是C++中引入的一種新的構(gòu)造函數(shù)。定義一個拷貝構(gòu)造函數(shù)的方式是:類名(const類名&形式參數(shù)){函數(shù)體}由此可看出拷貝構(gòu)造函數(shù)的特點(diǎn):(1)拷貝構(gòu)造函數(shù)的名稱與類的名稱相同,且它只有一個參數(shù),該參數(shù)就是對該類對象的引用。(2)拷貝構(gòu)造函數(shù)的功能是用于實(shí)現(xiàn)對象值的拷貝,通過將一個同類對象的值拷貝給一個新對象,來完成對新對象的初始化,即用一個對象去構(gòu)造另外一個對象。(3)每個類都有一個拷貝構(gòu)造函數(shù)7/27/202336拷貝構(gòu)造函數(shù):7/27/202336以本類對象為常量引用參數(shù)的構(gòu)造函數(shù):classDate{public:Date();
Date(constDate&d);//...};Datex;//調(diào)用無參構(gòu)造函數(shù)Datey(x);//調(diào)用拷貝構(gòu)造函數(shù)例:7/27/202337以本類對象為常量引用參數(shù)的構(gòu)造函數(shù):例:7/27/20233默認(rèn)拷貝構(gòu)造函數(shù):若類中沒有定義拷貝構(gòu)造函數(shù),則系統(tǒng)會悄悄定義一個默認(rèn)空拷貝構(gòu)造函數(shù):Date(constDate&d){}默認(rèn)拷貝構(gòu)造函數(shù)體一定是空的.空拷貝構(gòu)造函數(shù)負(fù)責(zé)將傳遞的對象到新創(chuàng)的對象做對象本體的位對位拷貝.(甚至連指針值都相等,即與參數(shù)對象擁有共同的資源)7/27/202338默認(rèn)拷貝構(gòu)造函數(shù):7/27/202338自定義拷貝構(gòu)造函數(shù):為了達(dá)到對象實(shí)體也就是對象整體復(fù)制目的,就需要另外定義一個拷貝構(gòu)造函數(shù),以覆蓋默認(rèn)的拷貝構(gòu)造函數(shù):見課本例315頁9.13自定義拷貝構(gòu)造名也是類名,它是構(gòu)造函數(shù)的重載,一旦自定義了拷貝構(gòu)造函數(shù),默認(rèn)的拷貝構(gòu)造函數(shù)就不再起作用了。在自定義拷貝構(gòu)造函數(shù)之前,我們進(jìn)行拷貝對象構(gòu)造時,都是在用默認(rèn)的拷貝構(gòu)造函數(shù),因?yàn)槟菚r的對象本體與對象實(shí)體是一致的。所以,自定義拷貝構(gòu)造函數(shù)在對象本體與對象實(shí)體不一致時,便是需要的,否則無此需要。7/27/202339自定義拷貝構(gòu)造函數(shù):為了達(dá)到對象實(shí)體也就是對象自定義拷貝構(gòu)造函數(shù)體的工作不負(fù)責(zé)位對位對象復(fù)制,一般來說,它負(fù)責(zé)資源分配和由此而來的指針修改.classPerson{
char*pName;public:Person(char*pN="noName"){pName=newchar[strlen(pN)+1];
if(pName)strcpy(pName,pN);}Person(constPerson&s){pName=newchar[strlen(s.pName)+1];
if(pName)strcpy(pName,s.pName);}~Person(){
delete[]pName;}};7/27/202340自定義拷貝構(gòu)造函數(shù)體的工作不負(fù)責(zé)位對位對象復(fù)制,一般來說,它6.析構(gòu)函數(shù)當(dāng)一個對象被定義時,系統(tǒng)自動調(diào)用構(gòu)造函數(shù)為該對象分配相應(yīng)的資源,當(dāng)對象使用完畢后,這些系統(tǒng)資源需要在對象消失前被釋放。人為的動態(tài)內(nèi)存釋放工作由析構(gòu)函數(shù)來完成,析構(gòu)函數(shù)時一種特殊的成員函數(shù),它的意義是做關(guān)于對象失效之前瞬間的善后工作。它的功能與構(gòu)造函數(shù)的工作正好相反,是用來釋放一個對象。我們知道有內(nèi)存申請,也就有內(nèi)存釋放。一般來說,需要定義構(gòu)造函數(shù)的類也需要定義析構(gòu)函數(shù),不需要構(gòu)造函數(shù)的類,也無須定義析構(gòu)函數(shù)。所以析構(gòu)函數(shù)和構(gòu)造函數(shù)是成對出現(xiàn)的。
7/27/2023416.析構(gòu)函數(shù)當(dāng)一個對象被定義時,系統(tǒng)自動調(diào)用析構(gòu)函數(shù)的定義方式為:~類名(){函數(shù)體}定義:特點(diǎn):(1)析構(gòu)函數(shù)名與構(gòu)造函數(shù)名相同,但它前面必須加一個“~”,用以與析構(gòu)函數(shù)相區(qū)別;(2)在定義析構(gòu)函數(shù)時,不能指定任何返回類型,也沒有參數(shù),而且不能重載。因此在一個類中只能有一個析構(gòu)函數(shù)。(3)析構(gòu)函數(shù)可以被用戶調(diào)用,也可以被系統(tǒng)調(diào)用。在下面兩種情況下,析構(gòu)函數(shù)會被自動調(diào)用7/27/202342析構(gòu)函數(shù)的定義方式為:定義:特點(diǎn):7/27/202342a、如果一個對象被定義在一個函數(shù)體內(nèi),則當(dāng)這個函數(shù)結(jié)束時,該對象的析構(gòu)函數(shù)被自動調(diào)用。b、當(dāng)一個對象是使用new運(yùn)算符動態(tài)創(chuàng)建時的,在使用delete運(yùn)算符自動釋放時,delete將會自動調(diào)用析構(gòu)函數(shù)。每一個類若沒有顯示地定義為一個類定義析構(gòu)函數(shù),編譯系統(tǒng)會自動地生成一個默認(rèn)的析構(gòu)函數(shù),默認(rèn)析構(gòu)函數(shù)時一個空函數(shù),實(shí)際上什么操作都不進(jìn)行。例:程序中三個類A、B、C分別有一個析構(gòu)函數(shù)。代碼如下:7/27/202343a、如果一個對象被定義在一個函數(shù)體內(nèi),則當(dāng)這個函數(shù)結(jié)束時,該classA{public:A(){cout<<"A->";}~A(){cout<<"<-~A";}};//-------------------------classB{public:B(){cout<<"B->";}~B(){cout<<"<-~B";}};//-------------------------classC{public:C(){cout<<"C->";}~C(){cout<<"<-~C";}};//-------------------------voidfunc(){cout<<"\nfunc:";Aa;cout<<"ok->";staticBb;Cc;}//----------------------------intmain(){cout<<"main:";for(inti=1;i<=2;++i){for(intj=1;j<=2;++j)if(i==2)Cc;elseAa;Bb;}func();func();}//=================7/27/202344classA{voidfunc(){7/27/20234注:(1)析構(gòu)函數(shù)總是出現(xiàn)在對象的生命期結(jié)束之時。靜態(tài)對象在程序運(yùn)行結(jié)束時析構(gòu)。(2)對于一個簡單的類來說,大多可以直接使用系統(tǒng)提供的默認(rèn)析構(gòu)函數(shù)。但是,如果在類的對象中分配有動態(tài)內(nèi)存(如:用new申請分配的內(nèi)容)時,就必須為該類提供適當(dāng)?shù)奈鰳?gòu)函數(shù),完成清理工作。(3)對象被析構(gòu)的順序與對象建立時的順序正好相反。對象析構(gòu)與構(gòu)造函數(shù)的關(guān)系是棧數(shù)據(jù)結(jié)構(gòu)中的入棧和出棧的關(guān)系,即最后構(gòu)造的對象先被析構(gòu)。棧底封閉指針7/27/202345注:棧底封閉指針7/27/2023457.對象轉(zhuǎn)型與賦值用于轉(zhuǎn)型的構(gòu)造函數(shù)5/8與5.0/8的結(jié)果是不同的,原因是C++執(zhí)行了兩種不同的操作。編譯器會將5.0/8中的整數(shù)8自動轉(zhuǎn)換成double,匹配兩個double數(shù)的除法操作。這是內(nèi)部數(shù)據(jù)類型所具有的轉(zhuǎn)換功能。但是,對于類類型,其自動轉(zhuǎn)換的功能必須編程實(shí)現(xiàn)。那就是定義一個含有一個參數(shù)的構(gòu)造函數(shù)。例:classStudent{public:Student(conststring&n);};voidfn(Student&s);intmain(){stringt=“jenny”;fn(t);//參數(shù)為string,卻能匹配Student類型}7/27/2023467.對象轉(zhuǎn)型與賦值用于轉(zhuǎn)型的構(gòu)造函數(shù)5/剛才的例子也是在告知,如何將string對象轉(zhuǎn)換成一個Student對象。如果有重載函數(shù):voidfn(string&s){cout<<“ok\n”;}則main函數(shù)中的fn(t)函數(shù)調(diào)用將會馬上匹配。否則,匹配了voidfn(Student&s)函數(shù)。從fn(Student&)和Student(conststring)可以推得fn(string)調(diào)用,這就是構(gòu)造函數(shù)用來從一種類型轉(zhuǎn)換成另一種類型的能力。對象轉(zhuǎn)型的規(guī)則:只會嘗試含有一個參數(shù)的構(gòu)造函數(shù)如果有二義性,則會放棄嘗試推導(dǎo)是一次性的,不允許多步推導(dǎo)7/27/202347剛才的例子也是在告知,如何將string對象對象拷貝對象賦值即對象拷貝:兩個已經(jīng)存在的對象之間的復(fù)制Persond(“Ranny”)Persong;d=g;//對象賦值對象賦值便是使用類中的賦值操作符.如果類中沒有定義賦值操作符,則系統(tǒng)悄悄地定義一個默認(rèn)的賦值操作符:Person&operator=(constPerson&p){memcpy(*this,*p,sizeof(p));}7/27/202348對象拷貝對象賦值即對象拷貝:兩個已經(jīng)存在的對象之7/27/2當(dāng)對象本體與對象實(shí)體不同時,則對象賦值操作符與拷貝構(gòu)造函數(shù)一樣,必須自定義:classPerson{
char*pName;public:Person(char*
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 廚房員工服務(wù)協(xié)議書
- 招生咨詢合同范例
- 屋頂補(bǔ)漏工程合同書
- 2024年車輛損害賠償協(xié)議書范本
- 技術(shù)服務(wù)聘用協(xié)議范本
- 最標(biāo)準(zhǔn)版商鋪?zhàn)赓U合同
- 2024收養(yǎng)人員入院協(xié)議書樣本
- 倉房租賃協(xié)議
- 定制外教聘請協(xié)議書
- 商標(biāo)設(shè)計協(xié)議書
- 釬探數(shù)據(jù)記錄
- 施工電梯安裝(拆卸)安全技術(shù)交底
- 北京應(yīng)急指揮系統(tǒng)建設(shè)
- 部編版一年級語文上冊第1課《秋天》精品課件【最新】
- 以“政府績效與公眾信任”為主題撰寫一篇小論文6篇
- 高校教師培訓(xùn)心得體會2000字3篇
- 電力專業(yè)標(biāo)準(zhǔn)化技術(shù)委員會管理細(xì)則
- 水泥用灰?guī)r礦礦產(chǎn)資源開發(fā)利用方案
- 老年友善醫(yī)院創(chuàng)建-老年人社會服務(wù)相關(guān)職責(zé)
- 高等天氣學(xué)講座---鋒生動力學(xué)和鋒面次級環(huán)流課件
- 液壓站更換作業(yè)指導(dǎo)書
評論
0/150
提交評論