版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
面向?qū)ο驝第四章第一頁(yè),共一百零八頁(yè),2022年,8月28日4.1.1定義類像枚舉和結(jié)構(gòu)一樣,類也是一種用戶自己構(gòu)造的數(shù)據(jù)類型并遵循C++的規(guī)定。類也要先聲明后使用;不管聲明的內(nèi)容是否相同,聲明同一個(gè)名字的兩個(gè)類是錯(cuò)誤的,類是具有惟一標(biāo)識(shí)符的實(shí)體;在類中聲明的任何成員不能使用extern、auto和register關(guān)鍵字進(jìn)行修飾;類中聲明的變量屬于該類,在某些情況下,變量可以被該類的不同實(shí)例所共享。類和其他數(shù)據(jù)類型不同的是,組成這種類型的不僅可以有數(shù)據(jù),而且可以有對(duì)數(shù)據(jù)進(jìn)行操作的函數(shù),它們分別叫做類的數(shù)據(jù)成員和類的成員函數(shù),而且不能在類聲明中對(duì)數(shù)據(jù)成員使用表達(dá)式進(jìn)行初始化。第二頁(yè),共一百零八頁(yè),2022年,8月28日1.聲明類類是對(duì)一組性質(zhì)相同對(duì)象的程序描述。在C++中聲明類的一般形式為:class類名{private:私有數(shù)據(jù)和函數(shù)public:公有數(shù)據(jù)和函數(shù)protected:保護(hù)數(shù)據(jù)和函數(shù)};類聲明以關(guān)鍵字class開(kāi)始,其后跟類名。類所聲明的內(nèi)容用花括號(hào)括起來(lái),右花括號(hào)后的分號(hào)作為類聲明語(yǔ)句的結(jié)束標(biāo)志。這一對(duì)花括號(hào)“{}”之間的內(nèi)容稱為類體。第三頁(yè),共一百零八頁(yè),2022年,8月28日類中定義的數(shù)據(jù)和函數(shù)稱為這個(gè)類的成員(數(shù)據(jù)成員和成員函數(shù))。類成員均具有一個(gè)屬性,叫做訪問(wèn)權(quán)限,通過(guò)它前面的關(guān)鍵字來(lái)定義。關(guān)鍵字private、public和protected以后的成員的訪問(wèn)權(quán)限分別是私有、公有和保護(hù)的,把這些成員分別叫做私有成員、公有成員和保護(hù)成員。訪問(wèn)權(quán)限用于控制對(duì)象的某個(gè)成員在程序中的可訪問(wèn)性,如果沒(méi)有使用關(guān)鍵字,則所有成員默認(rèn)聲明為private權(quán)限。這些關(guān)鍵字的使用順序和次數(shù)也都是任意的。第四頁(yè),共一百零八頁(yè),2022年,8月28日【例4.1】描述點(diǎn)的Point類。classPoint{//類名Pointprivate://聲明為私有訪問(wèn)權(quán)限intx,y;//私有數(shù)據(jù)成員public://聲明為公有訪問(wèn)權(quán)限voidSetxy(inta,intb);//無(wú)返回值的公有成員函數(shù)voidMove(inta,intb);//無(wú)返回值的公有成員函數(shù)voidDisplay();//無(wú)返回值的公有成員函數(shù)intGetx();//返回值為int的公有成員函數(shù)intGety();//返回值為int的公有成員函數(shù)};//類聲明以分號(hào)結(jié)束x和y是私有成員Setxy、Display、Move、Getx和Gety是公有成員因?yàn)橹皇锹暶骱瘮?shù),所以可只給出函數(shù)原型?!纠?.2】是其等效的聲明方式。第五頁(yè),共一百零八頁(yè),2022年,8月28日【例4.2】使用默認(rèn)關(guān)鍵字及改變關(guān)鍵字順序和次數(shù)的Point類。#include<iostream>usingnamespacestd;classPoint{//類名Pointintx;//默認(rèn)私有數(shù)據(jù)成員public://聲明為公有訪問(wèn)權(quán)限voidSetxy(int,int);//無(wú)返回值的公有成員函數(shù)的函數(shù)原型voidMove(int,int);//無(wú)返回值的公有成員函數(shù)的函數(shù)原型voidDisplay();//無(wú)返回值的公有成員函數(shù)的函數(shù)原型intGetx();//返回值為int的公有成員函數(shù)的函數(shù)原型intGety();//返回值為int的公有成員函數(shù)的函數(shù)原型private://聲明為私有訪問(wèn)權(quán)限inty;//私有數(shù)據(jù)成員};//類定義以分號(hào)結(jié)束由此可見(jiàn),成員函數(shù)聲明的規(guī)則與第3章所述的函數(shù)聲明規(guī)則相同。
第六頁(yè),共一百零八頁(yè),2022年,8月28日2.定義成員函數(shù)類中說(shuō)明的成員函數(shù)用來(lái)對(duì)數(shù)據(jù)成員進(jìn)行操作。在類中只對(duì)這些成員函數(shù)進(jìn)行了函數(shù)聲明,還必須在程序中實(shí)現(xiàn)這些成員函數(shù)。定義成員函數(shù)的一般形式為:
返回類型類名::成員函數(shù)名(參數(shù)列表){成員函數(shù)的函數(shù)體//內(nèi)部實(shí)現(xiàn)}其中“::”是作用域運(yùn)算符,“類名”是成員函數(shù)所屬類的名字,“::”用于表明其后的成員函數(shù)是屬于這個(gè)特定的類?!邦惷?:成員函數(shù)名”的意思就是對(duì)屬于“類名”的成員函數(shù)進(jìn)行定義,而“返回類型”則是這個(gè)成員函數(shù)返回值的類型。第七頁(yè),共一百零八頁(yè),2022年,8月28日定義成員函數(shù)的函數(shù)體。例如Setxy定義如下:voidPoint::Setxy(inta,intb){x=a;y=b;}定義Point的函數(shù)成員Setxy(inta,intb),該成員帶有兩個(gè)整型參數(shù),函數(shù)沒(méi)有返回值(void)。voidPoint::Move(inta,intb){x=x+a;y=y+b;}voidPoint::Display(){cout<<x<<","<<y<<endl;}intPoint::Getx(){returnx;}intPoint::Gety(){returny;}第八頁(yè),共一百零八頁(yè),2022年,8月28日
可以使用關(guān)鍵字inline將成員函數(shù)定義為內(nèi)聯(lián)函數(shù),例如:inlineintPoint::Getx(){returnx;}如果在聲明類的同時(shí),在類體內(nèi)給出成員函數(shù)的定義,則默認(rèn)為內(nèi)聯(lián)函數(shù)。例如在類中將聲明Getx的語(yǔ)句“intGetx();”改為“intGetx(){returnx;}”,則Getx為內(nèi)聯(lián)函數(shù)。一般直接在類體內(nèi)給出簡(jiǎn)單成員函數(shù)的定義。有些成員函數(shù)的實(shí)現(xiàn)方式不止一種,例如voidPoint::Display(){cout<<Getx()<<","<<Gety()<<endl;}是調(diào)用成員函數(shù)Getx()和Gety()實(shí)現(xiàn)的,它們使用了cout流,應(yīng)在定義之前包含如下語(yǔ)句:#include<iostream>usingnamespacestd;第九頁(yè),共一百零八頁(yè),2022年,8月28日3.數(shù)據(jù)成員的賦值不能在類體內(nèi)給數(shù)據(jù)成員賦值,即下面的方法是錯(cuò)誤的:ClassPoint{intx=25,y=56;……};當(dāng)然,在類體外面就更不允許了。數(shù)據(jù)成員的具體值是用來(lái)描述對(duì)象的屬性的。只有產(chǎn)生了一個(gè)具體的對(duì)象,這些數(shù)據(jù)值才有意義,所以又稱對(duì)象的初值或?qū)ο蟪跏蓟?。假設(shè)已經(jīng)有了一個(gè)對(duì)象A,則可使用“.”運(yùn)算符調(diào)用成員函數(shù)Setxy賦初值。例如:A.Setxy(25,56);將對(duì)象A的數(shù)據(jù)成員x和y分別賦給25和56,即A.x=25,A.y=56。
真正的初始化是使用與Point同名的構(gòu)造函數(shù)Point(int,int)實(shí)現(xiàn)的。產(chǎn)生Point對(duì)象的語(yǔ)句:PointA(25,56);第十頁(yè),共一百零八頁(yè),2022年,8月28日4.1.2使用類的對(duì)象及指針Point類是用戶定義的一種類型,使用Point在程序中聲明變量,具有Point類的類型的變量被稱為Point的對(duì)象。只有產(chǎn)生類的對(duì)象,才能使用這些數(shù)據(jù)和成員函數(shù)。類Point不僅可以聲明對(duì)象,還可以聲明對(duì)象的引用和對(duì)象的指針,語(yǔ)法與基本數(shù)據(jù)類型一樣。PointA,B;//定義Point類型的對(duì)象A和BPoint*p=&A;//定義指向?qū)ο驛的Point類型的指針Point&R=B;//定義R為Point類型對(duì)象B的引用
第十一頁(yè),共一百零八頁(yè),2022年,8月28日對(duì)象和引用都使用運(yùn)算符“.”訪問(wèn)對(duì)象的成員,指針則使用“->”運(yùn)算符。例如:A.Setxy(25,88);//為對(duì)象A設(shè)置初值p->Display();//顯示指針p所指對(duì)象A的數(shù)據(jù)成員//A.x和A.y之值R.Display();//顯示對(duì)象B的數(shù)據(jù)成員B.x和B.y之值【例4.3】根據(jù)上面對(duì)Point類的定義,演示使用Point類的對(duì)象。voidprint(Pointa)//使用Point的對(duì)象a作為函數(shù)參數(shù){a.Display();//顯示對(duì)象a的數(shù)據(jù)成員的值}voidmain()第十二頁(yè),共一百零八頁(yè),2022年,8月28日{(diào) PointA,B;//聲明對(duì)象 A.Setxy(25,55);//為對(duì)象A賦初值 B=A;//B的數(shù)據(jù)成員取A的數(shù)據(jù)成員之值 A.Display();//顯示A的數(shù)據(jù)成員 A.Move(-10,20);//移動(dòng)A print(A);//等價(jià)于A.Display(); print(B);//等價(jià)于B.Display() cout<<A.Getx()<<endl;//只能使用A.Getx(),//不能使用A.x}本例中的print函數(shù)使用Point的對(duì)象作為參數(shù)。C++推薦使用下面的引用的形式:voidprint(Point&a)//使用對(duì)象的引用做為函數(shù)參數(shù){a.Display();}//顯示引用對(duì)象a的數(shù)據(jù)成員之值第十三頁(yè),共一百零八頁(yè),2022年,8月28日對(duì)象A移動(dòng)之后,對(duì)象B仍為原來(lái)的值,所以輸出如下:25,55//原來(lái)的A和B15,75//新的A25,55//原來(lái)的B15//A.Getx()返回對(duì)象A的數(shù)據(jù)成員x的之值如果在print函數(shù)或主函數(shù)里使用如下語(yǔ)句,則產(chǎn)生錯(cuò)誤:cout<<A.x<<","<<A.y<<endl;//錯(cuò)誤!第十四頁(yè),共一百零八頁(yè),2022年,8月28日暫不涉及還沒(méi)有介紹的保護(hù)成員,可以歸納出如下規(guī)律:(1)類的成員函數(shù)可以直接使用自己類的私有成員(數(shù)據(jù)成員和成員函數(shù))。(2)類外面的函數(shù)不能直接訪問(wèn)類的私有成員(數(shù)據(jù)成員和成員函數(shù))。(3)類外面的函數(shù)只能通過(guò)類的對(duì)象使用該類的公有成員函數(shù),例如print和main函數(shù)。(4)類對(duì)象A和B的成員函數(shù)的代碼一樣,不同對(duì)象的區(qū)別是屬性的取值。第十五頁(yè),共一百零八頁(yè),2022年,8月28日在程序運(yùn)行時(shí),通過(guò)為對(duì)象分配內(nèi)存來(lái)創(chuàng)建對(duì)象。在創(chuàng)建對(duì)象時(shí),使用類作為樣板,故稱對(duì)象為類的實(shí)例。A和B兩個(gè)對(duì)象占據(jù)內(nèi)存中的不同區(qū)域。A的數(shù)據(jù)是A.x和A.y,而B(niǎo)的數(shù)據(jù)是B.x和B.y,它們各有表現(xiàn)自己的屬性數(shù)據(jù),但用來(lái)操作數(shù)據(jù)的代碼均是一樣的,例如A.Getx()和B.Getx()的代碼一樣。為節(jié)省內(nèi)存,在建立對(duì)象時(shí),只分配用于保存數(shù)據(jù)的內(nèi)存,代碼為每個(gè)對(duì)象共享。類中定義的代碼被放在計(jì)算機(jī)內(nèi)存的一個(gè)公用區(qū)中供該類的所有對(duì)象共享。
第十六頁(yè),共一百零八頁(yè),2022年,8月28日表4.1類Point的兩個(gè)實(shí)例A和B對(duì)象A對(duì)象B對(duì)象成員對(duì)象成員分配內(nèi)存內(nèi)容對(duì)象成員對(duì)象成員分配內(nèi)存內(nèi)容A.xA.x的值B.xB.x的值A(chǔ).yA.y的值B.yB.y的值A(chǔ).Setxy(int,int)Setxy函數(shù)代碼B.Setxy(int,int);Setxy函數(shù)代碼A.Move(int,int)Move函數(shù)代碼B.Move(int,int);Move函數(shù)代碼A.Display()Display函數(shù)代碼B.Display()Display函數(shù)代碼A.Getx()Getx函數(shù)代碼B.Getx()Getx函數(shù)代碼A.Gety()Gety函數(shù)代碼B.Gety()Gety函數(shù)代碼第十七頁(yè),共一百零八頁(yè),2022年,8月28日可以通過(guò)類對(duì)象的指針訪問(wèn)對(duì)象的成員。定義類對(duì)象指針的語(yǔ)法如下:
類名*對(duì)象指針名;對(duì)象指針名=對(duì)象的地址;也可以直接進(jìn)行初始化。例如:類名*對(duì)象指針名=對(duì)象的地址;類對(duì)象的指針可以通過(guò)“->”運(yùn)算符訪問(wèn)對(duì)象的成員,即:
對(duì)象指針名->對(duì)象成員名第十八頁(yè),共一百零八頁(yè),2022年,8月28日【例4.4】演示使用內(nèi)聯(lián)函數(shù)定義Point類及使用Point類指針和引用的完整例子。#include<iostream>//包含頭文件usingnamespacestd;//聲明命名空間classPoint{//使用內(nèi)聯(lián)函數(shù)定義類Pointprivate://聲明為私有訪問(wèn)權(quán)限 intx,y;//私有數(shù)據(jù)成員public://聲明為公有訪問(wèn)權(quán)限voidSetxy(inta,intb)//無(wú)返回值的內(nèi)聯(lián)公有成員函數(shù){x=a;y=b;}voidMove(inta,intb)//無(wú)返回值的內(nèi)聯(lián)公有成員函數(shù){x=x+a;y=y+b;}voidDisplay()//無(wú)返回值的內(nèi)聯(lián)公有成員函數(shù){cout<<x<<","<<y<<endl;}intGetx(){returnx;}//返回值為int的內(nèi)聯(lián)公有成員函數(shù)intGety(){returny;}//返回值為int的內(nèi)聯(lián)公有成員函數(shù)};//類定義以分號(hào)結(jié)束voidprint(Point*a)//類指針作為print函數(shù)的參數(shù)定義重載函數(shù){a->Display();}voidprint(Point&a)//類引用作為print函數(shù)的參數(shù)定義重載函數(shù){a.Display();}第十九頁(yè),共一百零八頁(yè),2022年,8月28日voidmain()//主函數(shù){PointA,B,*p;//聲明對(duì)象和指針Point&RA=A;//聲明對(duì)象RA引用對(duì)象AA.Setxy(25,55);//使用成員函數(shù)為對(duì)象A賦值B=A;//使用賦值運(yùn)算符為對(duì)象B賦值p=&B;//類Point的指針指向?qū)ο驜p->Setxy(112,115);//使用指針調(diào)用函數(shù)Setxy//重新設(shè)置B的值print(p);//傳遞指針顯示對(duì)象B的屬性p->Display();//再次顯示對(duì)象B的屬性RA.Move(-80,23);//引用對(duì)象RA調(diào)用Move函數(shù)print(A);//驗(yàn)證RA和A同步變化print(&A);//直接傳遞A的地址作為指針參數(shù)}第二十頁(yè),共一百零八頁(yè),2022年,8月28日程序運(yùn)行結(jié)果如下:112,115112,115-55,78-55,78由此可見(jiàn),使用對(duì)象和對(duì)象指針的效果一樣。第二十一頁(yè),共一百零八頁(yè),2022年,8月28日4.1.4數(shù)據(jù)封裝面向?qū)ο蟮某绦蛟O(shè)計(jì),是通過(guò)為數(shù)據(jù)和代碼建立分塊的內(nèi)存區(qū)域,以便提供對(duì)程序進(jìn)行模塊化的一種程序設(shè)計(jì)方法,這些模塊可以被用做樣板,在需要時(shí)再建立其副本。根據(jù)這個(gè)定義,對(duì)象是計(jì)算機(jī)內(nèi)存中的一塊區(qū)域,通過(guò)將內(nèi)存分塊,每個(gè)模塊(即對(duì)象)在功能上保持相對(duì)獨(dú)立。另外,定義也表明如下問(wèn)題:①這些內(nèi)存塊中不但存儲(chǔ)數(shù)據(jù),而且也存儲(chǔ)代碼,這對(duì)保證對(duì)象是受保護(hù)的這一點(diǎn)很重要。對(duì)象保護(hù)它自己不受未知的外部事件的影響,從而使自己的數(shù)據(jù)和功能不會(huì)因此遭到破壞。第二十二頁(yè),共一百零八頁(yè),2022年,8月28日②這些內(nèi)存塊的結(jié)構(gòu)可被用做樣板產(chǎn)生對(duì)象的更多副本。例如,一旦定義了一個(gè)窗口對(duì)象,只要內(nèi)存允許,就可以建立許多這樣的對(duì)象。在面向?qū)ο蟮某绦蛑?,?duì)象的行為只有向?qū)ο蟀l(fā)送消息才能引用,例如通過(guò)Display發(fā)出顯示消息,所以說(shuō)面向?qū)ο笫窍⑻幚頇C(jī)制。面向?qū)ο缶褪菍⑹澜缈闯墒怯梢唤M彼此相關(guān)并能相互通信的實(shí)體即對(duì)象組成的。程序中的對(duì)象映射現(xiàn)實(shí)世界中的對(duì)象。
第二十三頁(yè),共一百零八頁(yè),2022年,8月28日C++對(duì)其對(duì)象的數(shù)據(jù)成員和成員函數(shù)的訪問(wèn)是通過(guò)訪問(wèn)控制權(quán)限來(lái)限制的。private是限制類之外的函數(shù)的訪問(wèn)權(quán)。只要將數(shù)據(jù)成員或成員函數(shù)使用private限定,就設(shè)定了一道防線。它還必須留下與外面打交道的接口,這通過(guò)具有public權(quán)限的成員函數(shù)實(shí)現(xiàn)。在C++中,數(shù)據(jù)封裝是通過(guò)類來(lái)實(shí)現(xiàn)的。在類中指定了各成員的訪問(wèn)權(quán)限。一般情況下:將數(shù)據(jù)成員說(shuō)明為私有的,以便隱藏?cái)?shù)據(jù);將部分成員函數(shù)說(shuō)明為公有的,用于提供外界和這個(gè)類的對(duì)象相互作用的接口(界面),從而使得其他函數(shù)(例如main函數(shù))也可以訪問(wèn)和處理該類的對(duì)象。對(duì)于那些僅是為支持公有函數(shù)的實(shí)現(xiàn)而不作為對(duì)象界面的成員函數(shù),也將它們說(shuō)明為私有的。第二十四頁(yè),共一百零八頁(yè),2022年,8月28日4.2構(gòu)造函數(shù)建立一個(gè)對(duì)象時(shí),對(duì)象的狀態(tài)(數(shù)據(jù)成員的取值)是不確定的。為了使對(duì)象的狀態(tài)確定,必須對(duì)其進(jìn)行正確的初始化。C++有一個(gè)稱為構(gòu)造函數(shù)的特殊成員函數(shù),它可自動(dòng)進(jìn)行對(duì)象的初始化。第二十五頁(yè),共一百零八頁(yè),2022年,8月28日4.2.1默認(rèn)構(gòu)造函數(shù)當(dāng)沒(méi)有為一個(gè)類定義任何構(gòu)造函數(shù)的情況下,C++編譯器總要自動(dòng)建立一個(gè)不帶參數(shù)的構(gòu)造函數(shù)。例如,如果在上面的例子中沒(méi)有為Point類定義任何構(gòu)造函數(shù),則C++編譯器要為它產(chǎn)生一個(gè)默認(rèn)構(gòu)造函數(shù),這個(gè)默認(rèn)構(gòu)造函數(shù)具有下面這種形式:Point::Point(){}即它的函數(shù)體是空的。因此,當(dāng)建立Point類的一個(gè)對(duì)象時(shí),對(duì)象的狀態(tài)是不確定的,即沒(méi)有被初始化。
第二十六頁(yè),共一百零八頁(yè),2022年,8月28日
一旦程序定義了自己的構(gòu)造函數(shù),系統(tǒng)就不再提供這個(gè)默認(rèn)構(gòu)造函數(shù)。如果程序員沒(méi)有定義一個(gè)無(wú)參數(shù)的構(gòu)造函數(shù),但又聲明了一個(gè)沒(méi)有初始化的對(duì)象(如“PointA;”),則因系統(tǒng)已經(jīng)不再提供默認(rèn)構(gòu)造函數(shù),編譯就會(huì)出錯(cuò)?!澳J(rèn)”也稱為“缺省”,本書統(tǒng)一使用“默認(rèn)”。不帶參數(shù)的構(gòu)造函數(shù)又稱作默認(rèn)構(gòu)造函數(shù)。如果只聲明對(duì)象數(shù)組(即不提供初值),因?yàn)槊總€(gè)元素對(duì)象均需要調(diào)用一次默認(rèn)構(gòu)造函數(shù)來(lái)為自己初始化,所以必須要求有一個(gè)默認(rèn)構(gòu)造函數(shù)。
第二十七頁(yè),共一百零八頁(yè),2022年,8月28日4.2.2定義構(gòu)造函數(shù)1.構(gòu)造函數(shù)的定義和使用方法構(gòu)造函數(shù)的作用是在對(duì)象被創(chuàng)建時(shí)使用特定的值構(gòu)造對(duì)象,或者說(shuō)將對(duì)象初始化為一個(gè)特定的狀態(tài)。在對(duì)象創(chuàng)建時(shí)由系統(tǒng)自動(dòng)調(diào)用。如果程序中未聲明,則系統(tǒng)自動(dòng)產(chǎn)生出一個(gè)默認(rèn)形式的構(gòu)造函數(shù)允許為內(nèi)聯(lián)函數(shù)、重載函數(shù)、帶默認(rèn)形參值的函數(shù)。第二十八頁(yè),共一百零八頁(yè),2022年,8月28日構(gòu)造函數(shù)的特點(diǎn)構(gòu)造函數(shù)名與類名相同;沒(méi)有返回值;定義在public下;構(gòu)造函數(shù)由系統(tǒng)自動(dòng)調(diào)用;若不顯式定義,系統(tǒng)自動(dòng)生成一個(gè)不帶參數(shù)的構(gòu)造函數(shù);顯式定義了構(gòu)造函數(shù)后,默認(rèn)的構(gòu)造函數(shù)不起作用;構(gòu)造函數(shù)可以重載;第二十九頁(yè),共一百零八頁(yè),2022年,8月28日【例4.5】構(gòu)造函數(shù)的定義和執(zhí)行過(guò)程實(shí)例程序。#include<iostream>usingnamespacestd;classPoint{private:intx,y;public:Point();//聲明不帶參數(shù)的構(gòu)造函數(shù) Point(int,int);//聲明帶2個(gè)參數(shù)的構(gòu)造函數(shù)};Point::Point():x(0),y(0)//定義不帶參數(shù)的構(gòu)造函數(shù){cout<<"Initializingdefault"<<endl;}//定義帶2個(gè)參數(shù)的構(gòu)造函數(shù)Point::Point(inta,intb):x(a),y(b){cout<<"Initializing"<<a<<","<<b<<endl;}第三十頁(yè),共一百零八頁(yè),2022年,8月28日voidmain(){PointA;//使用不帶參數(shù)的構(gòu)造函數(shù)產(chǎn)生對(duì)象APointB(15,25);//使用帶參數(shù)的構(gòu)造函數(shù)產(chǎn)生對(duì)象BPointc[2];//使用不帶參數(shù)的構(gòu)造函數(shù)產(chǎn)生對(duì)象數(shù)組CPointD[2]={Point(5,7),Point(8,12)};//使用帶參數(shù)//的構(gòu)造函數(shù)產(chǎn)生對(duì)象數(shù)組D}第三十一頁(yè),共一百零八頁(yè),2022年,8月28日程序輸出結(jié)果如下:InitializingdefaultInitializing15,25InitializingdefaultInitializingdefaultInitializing5,7Initializing8,12程序中和Point類同名的兩個(gè)成員函數(shù)是構(gòu)造函數(shù):一個(gè)不帶參數(shù),另一個(gè)帶有2個(gè)參數(shù)。第三十二頁(yè),共一百零八頁(yè),2022年,8月28日構(gòu)造函數(shù)可以通過(guò)構(gòu)造函數(shù)的初始化列表給其數(shù)據(jù)成員賦值Point::Point(inta,intb):x(a),y(b)完成“x=a,y=b”的功能,它與下面的方法等價(jià):Point::Point(int,intb){x=a;y=b;cout<<"Initializing"<<a<<","<<b<<endl;}第三十三頁(yè),共一百零八頁(yè),2022年,8月28日構(gòu)造函數(shù)在類體里的聲明形式如下:
類名(形參1,形參2,…形參n);//可以沒(méi)有形參構(gòu)造函數(shù)在類體外定義??梢允褂贸跏蓟斜砘蛘咴跇?gòu)造函數(shù)的函數(shù)體內(nèi)定義數(shù)據(jù)成員的初值。假設(shè)數(shù)據(jù)成員為x1,x2,…,xn,則有如下兩種形式:
類名::類名(形參1,形參2,…形參n):x1(形參1),x2(形參2),…,xn(形參n){}類名::類名(形參1,形參2,…形參n){x1=形參1;x2=形參2;……xn=形參n;}構(gòu)造函數(shù)的參數(shù)是無(wú)順序排列,只要保證相互的對(duì)應(yīng)順序即可。可使用默認(rèn)參數(shù)或重載。第三十四頁(yè),共一百零八頁(yè),2022年,8月28日當(dāng)聲明一個(gè)外部對(duì)象時(shí),外部對(duì)象只是引用在其他地方聲明的對(duì)象,程序并不為外部對(duì)象說(shuō)明調(diào)用構(gòu)造函數(shù)。如果是全局對(duì)象或靜態(tài)對(duì)象,在main函數(shù)執(zhí)行之前要調(diào)用它們的構(gòu)造函數(shù),使用下面的主程序演示全局對(duì)象的情況:【例4.6】使用前面定義的Point類演示全局對(duì)象的例子。Pointglobal(5,7);voidmain(){cout<<"Enteringmainandexitingmain“<<endl;}程序在進(jìn)入main函數(shù)之前先構(gòu)造全局對(duì)象,輸出“Initializing5,7”。進(jìn)入主函數(shù)之后輸出為:Enteringmainandexitingmain。第三十五頁(yè),共一百零八頁(yè),2022年,8月28日2.自動(dòng)調(diào)用構(gòu)造類成員函數(shù)程序員不能在程序中顯式地調(diào)用構(gòu)造類成員函數(shù),這類函數(shù)是自動(dòng)調(diào)用的。Pointa.Point(x,y);錯(cuò)誤Pointa(x,y);。正確編譯系統(tǒng)會(huì)自動(dòng)調(diào)用Point(x,y)產(chǎn)生對(duì)象a并使用x和y將其正確地初始化。也不能在產(chǎn)生對(duì)象a之后,使用構(gòu)造函數(shù)改變對(duì)象的屬性值。a.Point(x,y);錯(cuò)誤如果要改變對(duì)象的屬性值,需要設(shè)計(jì)專門的成員函數(shù),如使用a.Setxy(x,y)改變對(duì)象的屬性值。第三十六頁(yè),共一百零八頁(yè),2022年,8月28日4.2.3構(gòu)造函數(shù)和運(yùn)算符new運(yùn)算符new用于建立生存期可控的對(duì)象并返回這個(gè)對(duì)象的指針。使用new建立動(dòng)態(tài)對(duì)象的語(yǔ)法和建立動(dòng)態(tài)變量的情況類似,其不同點(diǎn)是new和構(gòu)造函數(shù)一同起作用?!纠?.7】使用前面的Point類演示new運(yùn)算符和構(gòu)造函數(shù)的關(guān)系的例子。voidmain(){Point*ptr1=newPoint;Point*ptr2=newPoint(5,7);deleteptr1;deleteptr2;}運(yùn)行這個(gè)程序,程序的輸出結(jié)果是:InitializingdefaultInitializing5,7第三十七頁(yè),共一百零八頁(yè),2022年,8月28日當(dāng)使用new建立一個(gè)動(dòng)態(tài)對(duì)象時(shí),new首先分配足以保存Point類的一個(gè)對(duì)象所需要的內(nèi)存,然后自動(dòng)調(diào)用構(gòu)造函數(shù)來(lái)初始化這塊內(nèi)存,再返回這個(gè)動(dòng)態(tài)對(duì)象的地址。使用new建立的動(dòng)態(tài)對(duì)象在不用時(shí)必須用delete刪除,以便釋放所占空間。第三十八頁(yè),共一百零八頁(yè),2022年,8月28日4.2.4構(gòu)造函數(shù)的默認(rèn)參數(shù)如果程序定義自己的有參數(shù)構(gòu)造函數(shù),又想使用無(wú)參數(shù)形式的構(gòu)造函數(shù),解決的方法是將相應(yīng)的構(gòu)造函數(shù)全部使用默認(rèn)參數(shù)設(shè)計(jì)。
第三十九頁(yè),共一百零八頁(yè),2022年,8月28日【例4.8】設(shè)計(jì)構(gòu)造函數(shù)的默認(rèn)參數(shù)。#include<iostream>usingnamespacestd;classPoint{private:intx,y;public:Point(int=0,int=0);//聲明兩個(gè)參數(shù)均為默認(rèn)參數(shù)};Point::Point(inta,intb):x(a),y(b)//定義構(gòu)造函數(shù){cout<<"Initializing"<<a<<","<<b<<endl;}第四十頁(yè),共一百零八頁(yè),2022年,8月28日voidmain(){PointA;//構(gòu)造函數(shù)產(chǎn)生對(duì)象APointB(15,25);//構(gòu)造函數(shù)產(chǎn)生對(duì)象BPointc[2];//構(gòu)造函數(shù)產(chǎn)生對(duì)象數(shù)組C}聲明構(gòu)造函數(shù)原型時(shí)不需要給出參數(shù)名,即使用“int=0,int=0”。程序輸出如下:Initializing0,0Initializing15,25Initializing0,0Initializing0,0第四十一頁(yè),共一百零八頁(yè),2022年,8月28日4.2.5復(fù)制構(gòu)造函數(shù)引用在類中一個(gè)很重要的用途是用在復(fù)制構(gòu)造函數(shù)中。這是一類特殊而且重要的函數(shù),通常用于使用已有的對(duì)象來(lái)建立一個(gè)新對(duì)象。淺拷貝就是普通的數(shù)值復(fù)制。在通常情況下,編譯器建立一個(gè)默認(rèn)復(fù)制構(gòu)造函數(shù),這個(gè)復(fù)制構(gòu)造函數(shù)采用淺拷貝來(lái)使用已有的對(duì)象來(lái)建立新對(duì)象,所以又直譯為拷貝構(gòu)造函數(shù)。第四十二頁(yè),共一百零八頁(yè),2022年,8月28日對(duì)類A而言,復(fù)制(拷貝)構(gòu)造函數(shù)的原型為:
A::A(A&)首先它是一個(gè)構(gòu)造函數(shù)。其次,它的參數(shù)有些特別,是引用類自己的對(duì)象,即用一個(gè)已有的對(duì)象來(lái)創(chuàng)建一個(gè)新對(duì)象。為了不改變?cè)袑?duì)象,更普通的形式是使用const限定: A::A(constA&)但如果存在指針時(shí),是簡(jiǎn)單地將兩個(gè)指針指向同一地址還是指向不同的存儲(chǔ)區(qū)域?簡(jiǎn)單的賦值可能使兩個(gè)指針指向了同一塊存儲(chǔ)區(qū)域。當(dāng)一個(gè)指針?shù)N毀后,另外一個(gè)指針指向了無(wú)效區(qū)域,訪問(wèn)這個(gè)指針可能會(huì)引起嚴(yán)重的錯(cuò)誤。
第四十三頁(yè),共一百零八頁(yè),2022年,8月28日為了克服這樣的缺點(diǎn),需要自定義復(fù)制構(gòu)造函數(shù)。復(fù)制構(gòu)造函數(shù)的原型為:
Point(Point&);//復(fù)制構(gòu)造函數(shù)它的定義如下:
Point::Point(Point&t){x=t.x;y=t.y;}這個(gè)成員函數(shù)具有特殊的作用:在使用該類的一個(gè)對(duì)象初始化該類的另一個(gè)對(duì)象時(shí),調(diào)用這個(gè)函數(shù)(有時(shí)又稱為復(fù)制初始化構(gòu)造函數(shù))。例如:
Pointobj1(25,52);
Pointobj2(obj1);//使用obj1的數(shù)據(jù)成員初始化obj2,//即數(shù)據(jù)成員為25和52為了安全起見(jiàn),推薦使用的原型為:
Point(constPoint&)第四十四頁(yè),共一百零八頁(yè),2022年,8月28日4.3析構(gòu)函數(shù)在對(duì)象消失時(shí),使用析構(gòu)函數(shù)釋放由構(gòu)造函數(shù)分配的內(nèi)存。第四十五頁(yè),共一百零八頁(yè),2022年,8月28日4.3.1定義析構(gòu)函數(shù)它也是一種特殊的成員函數(shù),執(zhí)行與構(gòu)造函數(shù)相反的操作,通常用于撤消對(duì)象時(shí)的一些清理任務(wù),如釋放分配給對(duì)象的內(nèi)存空間等。具有一些特殊的性質(zhì):與類名相同,但前面必須加一個(gè)波浪號(hào)(~);沒(méi)有參數(shù),也沒(méi)有返回值,而且不能重載。因此在一個(gè)類中只能有一個(gè)析構(gòu)函數(shù);當(dāng)撤消對(duì)象時(shí),編譯系統(tǒng)會(huì)自動(dòng)地調(diào)用析構(gòu)函數(shù)。如果不顯式定義,系統(tǒng)自動(dòng)生成一個(gè)空的析構(gòu)函數(shù)
第四十六頁(yè),共一百零八頁(yè),2022年,8月28日例如:Point::~Point(){cout<<"Destructorisactive"<<endl;}使用下面的測(cè)試程序說(shuō)明析構(gòu)函數(shù)的作用:voidmain(){PointA(5,68);cout<<"Exitingmain"<<endl;}執(zhí)行此程序,其輸出是:Initializing5,68//調(diào)用構(gòu)造函數(shù)Exitingmain//主程序輸出Destructorisactive//自動(dòng)調(diào)用析構(gòu)函數(shù)當(dāng)對(duì)象的生存期結(jié)束時(shí),程序?yàn)檫@個(gè)對(duì)象調(diào)用析構(gòu)函數(shù),然后回收這個(gè)對(duì)象占用的內(nèi)存。全局對(duì)象和靜態(tài)對(duì)象的析構(gòu)函數(shù)在程序運(yùn)行結(jié)束之前調(diào)用。全局對(duì)象數(shù)組和靜態(tài)對(duì)象數(shù)組的析構(gòu)函數(shù)在程序結(jié)束之前被調(diào)用。數(shù)組的每個(gè)元素調(diào)用一次析構(gòu)函數(shù)。第四十七頁(yè),共一百零八頁(yè),2022年,8月28日4.3.2析構(gòu)函數(shù)和運(yùn)算符delete運(yùn)算符delete與析構(gòu)函數(shù)一起工作。當(dāng)使用運(yùn)算符delete刪除一個(gè)動(dòng)態(tài)對(duì)象時(shí),它首先為這個(gè)動(dòng)態(tài)對(duì)象調(diào)用析構(gòu)函數(shù),然后再釋放這個(gè)動(dòng)態(tài)對(duì)象占用的內(nèi)存,這和使用new建立動(dòng)態(tài)對(duì)象的過(guò)程正好相反?!纠?.9】使用Point類演示建立和釋放一個(gè)動(dòng)態(tài)對(duì)象數(shù)組的例子。#include<iostream>usingnamespacestd;classPoint{private:intx,y;
第四十八頁(yè),共一百零八頁(yè),2022年,8月28日public:Point(int=0,int=0);//聲明兩個(gè)參數(shù)均為默認(rèn)參數(shù)~Point();//聲明析構(gòu)函數(shù)};Point::Point(inta,intb):x(a),y(b)//定義構(gòu)造函數(shù){cout<<"Initializing"<<a<<","<<b<<endl;}Point::~Point()//定義析構(gòu)函數(shù){cout<<"Destructorisactive"<<endl;}voidmain(){ Point*ptr=newPoint[2]; delete[]ptr;}第四十九頁(yè),共一百零八頁(yè),2022年,8月28日程序的輸出如下:Initializing0,0//調(diào)用構(gòu)造函數(shù)Initializing0,0//調(diào)用構(gòu)造函數(shù)Destructorisactive//調(diào)用析構(gòu)函數(shù)Destructorisactive//調(diào)用析構(gòu)函數(shù)C++使用“[]”號(hào)來(lái)說(shuō)明這是動(dòng)態(tài)對(duì)象數(shù)組即語(yǔ)句delete[]ptr;//注意不要錯(cuò)為ptr[],而且[]號(hào)內(nèi)為空delete將為動(dòng)態(tài)數(shù)組的每個(gè)對(duì)象調(diào)用一次析構(gòu)函數(shù),然后釋放ptr所指向的內(nèi)存。當(dāng)程序先后創(chuàng)建幾個(gè)對(duì)象時(shí),系統(tǒng)按后建先析構(gòu)的原則析構(gòu)對(duì)象。當(dāng)使用delete調(diào)用析構(gòu)函數(shù)時(shí),則按delete的順序析構(gòu)。第五十頁(yè),共一百零八頁(yè),2022年,8月28日4.3.3默認(rèn)析構(gòu)函數(shù)如果在定義類時(shí)沒(méi)有定義析構(gòu)函數(shù),C++編譯器要為這個(gè)類產(chǎn)生一個(gè)默認(rèn)的析構(gòu)函數(shù),正如沒(méi)有給類定義構(gòu)造函數(shù),C++編譯系統(tǒng)會(huì)產(chǎn)生一個(gè)默認(rèn)構(gòu)造函數(shù)一樣,編譯器也為它產(chǎn)生一個(gè)函數(shù)體為空的默認(rèn)析構(gòu)函數(shù):Test::~Test(){}第五十一頁(yè),共一百零八頁(yè),2022年,8月28日4.4調(diào)用復(fù)制構(gòu)造函數(shù)的綜合實(shí)例
調(diào)用復(fù)制構(gòu)造函數(shù)的情況當(dāng)用類的一個(gè)對(duì)象去初始化該類的另一個(gè)對(duì)象時(shí),系統(tǒng)自動(dòng)調(diào)用復(fù)制構(gòu)造函數(shù)實(shí)現(xiàn)拷貝賦值。Pointp2(p1);//用對(duì)象p1初始化對(duì)象p2,復(fù)制構(gòu)造函數(shù)被調(diào)用(代入法)Pointp3=p1;//用對(duì)象p1初始化對(duì)象p3,復(fù)制構(gòu)造函數(shù)被調(diào)用(賦值法)第五十二頁(yè),共一百零八頁(yè),2022年,8月28日當(dāng)函數(shù)的形參是類的對(duì)象,調(diào)用函數(shù),進(jìn)行形參和實(shí)參結(jié)合時(shí)。voidfun1(Pointp){cout<<p.GetX()<<endl;}voidmain(){PointA(1,2);fun1(A);//調(diào)用復(fù)制構(gòu)造函數(shù)}當(dāng)函數(shù)的返回值是對(duì)象,函數(shù)執(zhí)行完成,返回調(diào)用者時(shí)。Pointfun2(){PointA(1,2);returnA;//調(diào)用復(fù)制構(gòu)造函數(shù)}voidmain(){PointB;B=fun2();}第五十三頁(yè),共一百零八頁(yè),2022年,8月28日【例4.10】演示調(diào)用構(gòu)造函數(shù)及析構(gòu)函數(shù)的綜合例子。#include<iostream>usingnamespacestd;classPoint{private: intX,Y;public: Point(inta=0,intb=0)//構(gòu)造函數(shù){X=a;Y=b;cout<<"Initializing"<<endl;}Point(constPoint&p);//復(fù)制構(gòu)造函數(shù)第五十四頁(yè),共一百零八頁(yè),2022年,8月28日intGetX(){returnX;}intGetY(){returnY;}voidShow(){cout<<"X="<<X<<",Y="<<Y<<endl;}~Point(){cout<<"delete..."<<X<<","<<Y<<endl;}};Point::Point(constPoint&p)//定義復(fù)制構(gòu)造函數(shù){ X=p.X; Y=p.Y; cout<<"CopyInitializing"<<endl;}voiddisplay(Pointp)//Point類的對(duì)象作為函數(shù)的形參{p.Show();}voiddisp(Point&p)//Point類對(duì)象的引用作為函數(shù)的形參{p.Show();}第五十五頁(yè),共一百零八頁(yè),2022年,8月28日Pointfun()//函數(shù)的返回值為Point類的對(duì)象{PointA(101,202);returnA;}voidmain(){PointA(42,35);//對(duì)象A//第1次調(diào)用復(fù)制構(gòu)造函數(shù)PointB(A); //①用A初始化BPointC(58,94);//對(duì)象Ccout<<"calleddisplay(B)"<<endl;//第2次調(diào)用復(fù)制構(gòu)造函數(shù)display(B); //②對(duì)象B作為display的實(shí)參
第五十六頁(yè),共一百零八頁(yè),2022年,8月28日cout<<"Next..."<<endl;cout<<"calleddisp(B)"<<endl;disp(B);cout<<"callC=fun()"<<endl;//第3次調(diào)用復(fù)制構(gòu)造函數(shù)C=fun(); //③fun的返回值賦給對(duì)象Ccout<<"calleddisp(C)"<<endl;disp(C);cout<<"out..."<<endl;}第五十七頁(yè),共一百零八頁(yè),2022年,8月28日輸出結(jié)果及注釋如下:Initializing//創(chuàng)建對(duì)象ACopyInitializing//調(diào)用復(fù)制構(gòu)造函數(shù),使用對(duì)象A初始化BInitializing//創(chuàng)建對(duì)象Ccalleddisplay(B)//用對(duì)象B作為參數(shù)CopyInitializing//需要調(diào)用復(fù)制構(gòu)造函數(shù)X=42,Y=35//進(jìn)入函數(shù)體執(zhí)行語(yǔ)句delete...42,35//退出函數(shù)時(shí),需要調(diào)用析構(gòu)函數(shù)清除對(duì)象Next...calleddisp(B)//使用引用做為參數(shù),則不需要//調(diào)用復(fù)制構(gòu)造函數(shù)X=42,Y=35//進(jìn)入函數(shù)體執(zhí)行語(yǔ)句callC=fun()//C使用函數(shù)fun()的返回值Initializing//在函數(shù)fun()內(nèi)創(chuàng)建對(duì)象ACopyInitializing//調(diào)用復(fù)制構(gòu)造函數(shù)返回值第五十八頁(yè),共一百零八頁(yè),2022年,8月28日delete...101,202//返回值給對(duì)象C,調(diào)用析構(gòu)函數(shù)//清除臨時(shí)對(duì)象delete...101,202//退出函數(shù)體,調(diào)用析構(gòu)函數(shù)清除//對(duì)象Acalleddisp(C)//使用引用做為參數(shù)X=101,Y=202//進(jìn)入函數(shù)體執(zhí)行語(yǔ)句out...delete...101,202//調(diào)用析構(gòu)函數(shù)清除對(duì)象Cdelete...42,35//調(diào)用析構(gòu)函數(shù)清除對(duì)象Bdelete...42,35//調(diào)用析構(gòu)函數(shù)清除對(duì)象Adelete...101,202//將值傳給對(duì)象C,調(diào)用析構(gòu)函數(shù)//清除臨時(shí)對(duì)象delete...101,202//退出函數(shù)體,調(diào)用析構(gòu)函數(shù)//清除對(duì)象A第五十九頁(yè),共一百零八頁(yè),2022年,8月28日第1句輸出比較簡(jiǎn)單,調(diào)用函數(shù)fun,在其內(nèi)調(diào)用構(gòu)造函數(shù)Point(int,int)創(chuàng)建對(duì)象A。對(duì)象A的生命期與函數(shù)fun同在,結(jié)束調(diào)用時(shí)則調(diào)用析構(gòu)函數(shù)析構(gòu)對(duì)象A。在這個(gè)構(gòu)造與析構(gòu)之間,還有一個(gè)過(guò)程發(fā)生,即執(zhí)行“returnA;”時(shí),目的是使得C=A,使C的數(shù)據(jù)成員與A的相同,但這要調(diào)用復(fù)制構(gòu)造函數(shù)實(shí)現(xiàn)。復(fù)制構(gòu)造函數(shù)是創(chuàng)建對(duì)象的,它產(chǎn)生一個(gè)臨時(shí)對(duì)象,用這個(gè)臨時(shí)對(duì)象完成C=A,然后再析構(gòu)這個(gè)臨時(shí)對(duì)象,這就是中間兩條輸出信息。這樣,語(yǔ)句“C=func();”就輸出如上4條信息。第六十頁(yè),共一百零八頁(yè),2022年,8月28日4.5成員函數(shù)重載及默認(rèn)參數(shù)【例4.11】構(gòu)造一個(gè)求4個(gè)正整數(shù)中最大者的類Max,并用主程序驗(yàn)證它的功能。classMax{//聲明類private://封裝數(shù)據(jù)成員和成員函數(shù)inta,b,c,d;//數(shù)據(jù)成員intMaxi(int,int);//只允許類內(nèi)部的成員函數(shù)調(diào)用public://對(duì)外界的接口voidSet(int,int,int,int);//設(shè)置對(duì)象初值intMaxi();//求最大值}A[3];//聲明類的對(duì)象數(shù)組,定義結(jié)束第六十一頁(yè),共一百零八頁(yè),2022年,8月28日//類中成員函數(shù)的實(shí)現(xiàn)intMax::Maxi(intx,inty) //求二個(gè)數(shù)的最大值{return(x>y)?x:y;}//使用兩個(gè)默認(rèn)參數(shù)voidMax::Set(intx1,intx2,intx3=0,intx4=0){a=x1;b=x2;c=x3;d=x4;}intMax::Maxi()//求自己類中四個(gè)數(shù)的最大值{ intx=Maxi(a,b);//x和y為Maxi()函數(shù)的局部整數(shù)對(duì)象inty=Maxi(c,d);returnMaxi(x,y);}第六十二頁(yè),共一百零八頁(yè),2022年,8月28日//主程序#include<iostream>usingnamespacestd;voidmain(){ A[0].Set(12,45,76,89);//為數(shù)組對(duì)象A[0]置初值 A[1].Set(12,45,76);//為數(shù)組對(duì)象A[1]置初值 A[2].Set(12,45);//為數(shù)組對(duì)象A[2]置初值for(inti=0;i<3;i++)//輸出對(duì)象求值結(jié)果cout<<A[i].Maxi()<<"";}第六十三頁(yè),共一百零八頁(yè),2022年,8月28日程序演示了可在聲明類的同時(shí)也聲明類的對(duì)象,這里是聲明對(duì)象數(shù)組A,作用與在主程序里使用“MaxA[3];”語(yǔ)句相同。為了提高可讀性,一般不在聲明類時(shí)聲明對(duì)象,這里只是為了演示它的性質(zhì)。程序輸出結(jié)果為:897645類中重載了函數(shù)Maxi,一個(gè)原型為Maxi(int,int),用來(lái)求兩數(shù)中的大者。因?yàn)樗槐蛔约旱某蓡T函數(shù)使用,所以定義為private。另一個(gè)原型為Maxi(),它調(diào)用兩次Maxi(int,int),然后再用這兩次的結(jié)果作為Maxi(int,int)的參數(shù),求出4個(gè)數(shù)中的最大值。賦值成員函數(shù)Set使用2個(gè)默認(rèn)參數(shù),是為了書寫方便。第六十四頁(yè),共一百零八頁(yè),2022年,8月28日4.6this指針在定義Point類的兩個(gè)對(duì)象A和B之后,當(dāng)執(zhí)行語(yǔ)句“A.Setxy(25,55);”時(shí),A.x和A.y就被賦值。但是,函數(shù)Setxy(int,int)作為代碼,在計(jì)算機(jī)里是和具體的對(duì)象分開(kāi)存儲(chǔ)的。那么,它是怎樣知道,是要對(duì)A進(jìn)行操作而不是對(duì)B進(jìn)行操作呢?當(dāng)執(zhí)行A.Setxy(25,55)時(shí),成員函數(shù)Setxy(int,int)有一個(gè)隱藏參數(shù),名為this指針。也就是說(shuō),源程序被編譯器編譯后,Setxy(inta,intb)實(shí)際上是如下形式:
voidPoint::Setxy(inta,intb,(Point*)this){this->x=a;this->y=b;}成員函數(shù)的this指針指向?qū)ο驛。成員中對(duì)x和y的引用表示是引用對(duì)象A的成員x和y。對(duì)于任何訪問(wèn)該成員函數(shù)的類的對(duì)象來(lái)說(shuō),C++編譯器都認(rèn)為是訪問(wèn)this指針?biāo)赶虻膶?duì)象中的成員。第六十五頁(yè),共一百零八頁(yè),2022年,8月28日C++規(guī)定,當(dāng)一個(gè)成員函數(shù)被調(diào)用時(shí),系統(tǒng)自動(dòng)向它傳遞一個(gè)隱含的參數(shù),該參數(shù)是一個(gè)指向接受該函數(shù)調(diào)用的對(duì)象的指針,從而使成員函數(shù)知道該對(duì)哪個(gè)對(duì)象進(jìn)行操作。在程序中,可以使用關(guān)鍵字this來(lái)引用該指針。使用this指針,保證了每個(gè)對(duì)象可以擁有自己的數(shù)據(jù)成員,但處理這些數(shù)據(jù)成員的代碼可以被所有的對(duì)象共享。除非特殊需要,一般情況下都省略符號(hào)“this->”,而讓系統(tǒng)進(jìn)行默認(rèn)設(shè)置。第六十六頁(yè),共一百零八頁(yè),2022年,8月28日4.7一個(gè)類的對(duì)象作為另一個(gè)類的成員因?yàn)轭惐旧砭褪且环N新的數(shù)據(jù)類型,所以一個(gè)類可以作為另一個(gè)類的成員。假設(shè)有A和B兩個(gè)類,可以通過(guò)在B類里定義A的對(duì)象作為B的數(shù)據(jù)成員,或者定義一個(gè)返回類型為A的函數(shù)作為B的成員函數(shù)。第六十七頁(yè),共一百零八頁(yè),2022年,8月28日假設(shè)定義了坐標(biāo)點(diǎn)的類Point,矩形類Rectangle的屬性需要一個(gè)坐標(biāo)點(diǎn)及長(zhǎng)和寬。一個(gè)Point的對(duì)象恰好可以作為矩形的頂點(diǎn)坐標(biāo),即Rectangle可以使用Point的一個(gè)對(duì)象作為數(shù)據(jù)成員。在Rectangle類中,用Point類定義一個(gè)返回Point類型指針的函數(shù)作為Rectangle的成員函數(shù)。
【例4.12】使用對(duì)象成員的例子。#include<iostream>usingnamespacestd;classPoint{//定義點(diǎn)類 intx,y; public: voidSet(inta,intb){x=a;y=b;} intGetx(){returnx;} intGety(){returny;}};第六十八頁(yè),共一百零八頁(yè),2022年,8月28日classRectangle{//在矩形類里使用Point類的成員PointLoc;//定義一個(gè)Point類的對(duì)象作為頂點(diǎn)intH,W;//H為高,W為寬public:voidSet(intx,inty,inth,intw);Point*GetLoc();//用Point類定義返回指針的函數(shù)intGetHeight(){returnH;}intGetWidth(){returnW;}};voidRectangle::Set(intx,inty,inth,intw){Loc.Set(x,y);//初始化坐標(biāo)頂點(diǎn)H=h;W=w;}Point*Rectangle::GetLoc()//返回類型Point*,作//為Rectangle的成員函數(shù){return&Loc;}//返回對(duì)象Loc的地址第六十九頁(yè),共一百零八頁(yè),2022年,8月28日voidmain(){Rectanglerect;rect.Set(10,2,25,20);cout<<rect.GetHeight()<<",“<<rect.GetWidth()<<",";Point*p=rect.GetLoc();//定義Point類的//指針對(duì)象p并初始化cout<<p->Getx()<<","<<p->Gety()<<endl;}新類Rectangle具有一個(gè)頂點(diǎn),所以也具有Point類的屬性。這就是類的結(jié)構(gòu)關(guān)系(聚合關(guān)系,有時(shí)又稱包含)。構(gòu)成的新類不能直接操作另一個(gè)類的數(shù)據(jù),必須通過(guò)原構(gòu)成類的對(duì)象使用它們的成員函數(shù)來(lái)實(shí)現(xiàn),本例使用Loc.Set(x,y)方式實(shí)現(xiàn)。程序輸出結(jié)果為:25,20,10,2第七十頁(yè),共一百零八頁(yè),2022年,8月28日4.8類和對(duì)象的性質(zhì)4.8.1類對(duì)象的性質(zhì)歸納對(duì)象的一些基本特性如下:①對(duì)象之間可以相互賦值。例如,如下語(yǔ)句使A和B的數(shù)據(jù)成員有相同的值:PointA,B;A.Setxy(25,55);B=A;②可使用對(duì)象數(shù)組。例如,“MaxA[3];”定義數(shù)組A可以存儲(chǔ)3個(gè)Point類的對(duì)象。③可使用指向?qū)ο蟮闹羔?,使用取地址運(yùn)算符&將一個(gè)對(duì)象的地址置于該指針中,如:Point*p=&A;p->Display();注意,不能取私有數(shù)據(jù)成員的地址,也不能取成員函數(shù)的地址。第七十一頁(yè),共一百零八頁(yè),2022年,8月28日④對(duì)象可以用做函數(shù)參數(shù),這時(shí)參數(shù)傳遞可以采用傳值方式,也可以傳址,采用對(duì)象的引用或指針作為參數(shù)。但是,如參數(shù)對(duì)象被修改,相應(yīng)的實(shí)參對(duì)象也將被修改。C++推薦使用引用作為參數(shù)傳遞。為了避免被調(diào)用函數(shù)修改原來(lái)對(duì)象的數(shù)據(jù)成員,可以使用const修飾符。⑤對(duì)象作為函數(shù)參數(shù)時(shí),可以使用對(duì)象值、對(duì)象引用和對(duì)象地址(指針)。以介紹過(guò)的print函數(shù)為例,它們的參數(shù)傳遞形式為:voidprint(Pointa){a.Display;}voidprint(Point&a){a.Display;}voidprint(Point*p){p->Display;}它們的原型分別print(Point);print(Point&);print(Point*);對(duì)于對(duì)象A,print(&A)調(diào)用的是原型為print(Point*)的函數(shù)形式。注意:參數(shù)為對(duì)象和引用時(shí),編譯系統(tǒng)無(wú)法區(qū)別,重載print只能選擇其中的一種。⑥一個(gè)對(duì)象可以用做另一個(gè)對(duì)象的成員。例如定義Point類的對(duì)象Loc為Rectangle的數(shù)據(jù)成員,GetLoc()作為返回Point類型指針的函數(shù)。第七十二頁(yè),共一百零八頁(yè),2022年,8月28日4.8.2類的性質(zhì)1.使用類的權(quán)限①類本身的成員函數(shù)可以使用類的所有成員(私有和公有成員)。②類的對(duì)象只能訪問(wèn)公有成員函數(shù),例如輸出x只能使用A.Getx()不能使用A.x。③其他函數(shù)不能使用類的私有成員,也不能使用公有成員函數(shù),它們只能通過(guò)類的對(duì)象使用公有成員函數(shù)。④一個(gè)類可以使用另外一個(gè)類的對(duì)象,這個(gè)類也只能通過(guò)那個(gè)類的對(duì)象使用該類的成員函數(shù),通過(guò)成員函數(shù)使用數(shù)據(jù)成員,例如Loc.Set(x,y)。第七十三頁(yè),共一百零八頁(yè),2022年,8月28日2.不完全的類聲明類不是內(nèi)存中的物理實(shí)體,只有當(dāng)使用類產(chǎn)生對(duì)象時(shí),才進(jìn)行內(nèi)存分配,這種對(duì)象建立的過(guò)程稱為實(shí)例化。應(yīng)當(dāng)注意的是:類必須在其成員被使用之前先進(jìn)行聲明。然而,有時(shí)也需要將類作為一個(gè)整體來(lái)使用,而不存取其成員。聲明指針就是這種情況,例如:classMembersOnly;//不完全的類聲明MembersOnly*club;//定義一個(gè)全局變量類指針voidmain(){…//函數(shù)體}//主函數(shù)classMembersOnly{…//類體};//完全定義該類第七十四頁(yè),共一百零八頁(yè),2022年,8月28日第一條語(yǔ)句稱為不完全類聲明,它用于在類沒(méi)有完全定義之前就引用該類的情況,可以聲明全局變量指針club。編譯器執(zhí)行到該指針的聲明處時(shí),只了解指針?biāo)割愋褪且粋€(gè)叫MembersOnly的類,而不了解其他任何情況。不完全聲明的類不能實(shí)例化,企圖實(shí)例化會(huì)產(chǎn)生編譯出錯(cuò)信息;不完全聲明僅用于類和結(jié)構(gòu),企圖存取沒(méi)有完全聲明的類成員,也會(huì)引起編譯出錯(cuò)信息。另外,將數(shù)據(jù)成員的聲明放在最后,有利于先理解類的界面。第七十五頁(yè),共一百零八頁(yè),2022年,8月28日3.空類盡管類的目的是封裝代碼和數(shù)據(jù),它也可以不包括任何聲明。例如:classEmpty{};當(dāng)然,這種類沒(méi)有任何行為,但可以產(chǎn)生空類對(duì)象。voidmain(){Emptyobject;}為什么要產(chǎn)生空類呢?在開(kāi)發(fā)大的項(xiàng)目時(shí),需要在一些類還沒(méi)有完全定義或?qū)崿F(xiàn)時(shí)進(jìn)行先期測(cè)試。這常稱為“插頭”,用來(lái)保證代碼能正確地被編譯,從而允許測(cè)試其中的一部分。不過(guò)這是早期的做法,對(duì)強(qiáng)類型檢查的編譯器,會(huì)給出一個(gè)警告??山o空類增加一個(gè)無(wú)參數(shù)構(gòu)造函數(shù)(見(jiàn)構(gòu)造函數(shù)一節(jié))以消除警告。例如:classEmpty{public:Empty(){}};第七十六頁(yè),共一百零八頁(yè),2022年,8月28日4.類作用域聲明類時(shí)所使用的一對(duì)花括號(hào)形成所謂的類作用域。在類作用域中聲明的標(biāo)識(shí)符只在類中可見(jiàn)。例如:classexample{intnum;};inti=num;//錯(cuò),num在此不可見(jiàn)intnum;//正確,num與類中說(shuō)明的數(shù)據(jù)//成員num具有不同的作用域第七十七頁(yè),共一百零八頁(yè),2022年,8月28日即使該成員函數(shù)的實(shí)現(xiàn)是在類定義之外給出的,類作用域也包含了類中成員函數(shù)的作用域classMyClass{intnumber;public:voidset(int);};intnumber;//這個(gè)number不屬于類MyClassvoidMyClass::set(inti){number=i;//使用類MyClass中的標(biāo)識(shí)符number}類中的一個(gè)成員名可以使用類名和作用域運(yùn)算符來(lái)顯式指定,這稱為成員名限定。例如:voidMyClass::set(inti){MyClass::number=i;//顯式指定訪問(wèn)MyClass//類中的標(biāo)識(shí)符number}第七十八頁(yè),共一百零八頁(yè),2022年,8月28日在程序中使用成員選擇運(yùn)算符(“.”或“->”)訪問(wèn)一個(gè)對(duì)象的成員時(shí),其后的名字是引用該對(duì)象所在類中聲明的成員名。例如:PointA;//聲明類對(duì)象,假設(shè)類//內(nèi)有成員函數(shù)Getx()intGetx(){return5;};//類外面聲明的函數(shù)intx=Getx();//訪問(wèn)函數(shù)Getx(),返回5inty=A.Getx();//訪問(wèn)類Point中聲明的//成員函數(shù)Getx()第七十九頁(yè),共一百零八頁(yè),2022年,8月28日除非編譯器在處理類聲明時(shí)遇到了標(biāo)識(shí)其結(jié)束的右花括號(hào),否則這個(gè)聲明仍然是引用性聲明。引用性聲明所聲明的類名不能用來(lái)建立對(duì)象,只能用來(lái)聲明指針或引用,或用在函數(shù)聲明中。例如:classMyClass{MyClassmember;//錯(cuò)MyClass*p;//正確};classYourClass{private:MyClassd;//正確};當(dāng)在類MyClass中聲明成員member時(shí),類名MyClass僅作了引用性聲明,因而這個(gè)語(yǔ)句是錯(cuò)誤的。第八十頁(yè),共一百零八頁(yè),2022年,8月28日4.9面向?qū)ο蟮臉?biāo)記圖為了設(shè)計(jì)、開(kāi)發(fā)和相互交流的需要,采用圖像形式將面向?qū)ο蟪绦蛟O(shè)計(jì)對(duì)問(wèn)題的描述直觀地表示出來(lái)。UML是一種可視化建模語(yǔ)言,主要用于面向?qū)ο蠓治龊徒?。本書主要是借助于它?lái)說(shuō)明類的有關(guān)知識(shí)。第八十一頁(yè),共一百零八頁(yè),2022年,8月28日4.9.1類和對(duì)象的UML標(biāo)記圖
類和對(duì)象的標(biāo)記符號(hào)類似,它們都只能表示靜態(tài)特征。如圖4.1所示,在UML語(yǔ)言中,類使用短式和長(zhǎng)式兩種方式表示。第八十二頁(yè),共一百零八頁(yè),2022年,8月28日短式僅用1個(gè)含有類名的長(zhǎng)方框表示。長(zhǎng)式使用3個(gè)方框表示。最上面的框中填入類的名稱,中間框中填入屬性(C++中稱為數(shù)據(jù)成員),最下面的框中填入成員函數(shù)(操作)。屬性和操作可以根據(jù)需要進(jìn)行細(xì)化。第八十三頁(yè),共一百零八頁(yè),2022年,8月28日?qǐng)D4.2對(duì)象的標(biāo)記圖對(duì)象的表示有3種方式,最簡(jiǎn)單的是只填寫對(duì)象名稱,完整的方式是給出對(duì)象名和類名(類名在右邊,兩者之間用冒號(hào)連接),并用下劃線將它們標(biāo)注出來(lái)。當(dāng)還沒(méi)有決定這個(gè)對(duì)象的名稱時(shí),可以不給出對(duì)象名,但不能省去“:”號(hào)。第八十四頁(yè),共一百零八頁(yè),2022年,8月28日4.9.2表示對(duì)象的結(jié)構(gòu)與連接只有定義和描述了對(duì)象類之間的關(guān)系,各個(gè)對(duì)象類才能構(gòu)成一個(gè)整體的、有機(jī)的系統(tǒng)模型,這就是對(duì)象類的結(jié)構(gòu)與連結(jié)關(guān)系。對(duì)象結(jié)構(gòu)是指對(duì)象之間的分類(繼承)關(guān)系和組成(聚合)關(guān)系,統(tǒng)稱為關(guān)聯(lián)關(guān)系。對(duì)象之間的靜態(tài)關(guān)系是通過(guò)對(duì)象屬性之間的連接反映的,稱為實(shí)例連接。對(duì)象行為之間的動(dòng)態(tài)關(guān)系是通過(guò)對(duì)象行為(消息)之間的依賴關(guān)系表現(xiàn)的,稱之為消息連接,又統(tǒng)稱為連接。
第八十五頁(yè),共一百零八頁(yè),2022年,8月28日1.分類關(guān)系及其表示
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年受歡迎人事代理合同
- 2025年生態(tài)環(huán)保技術(shù)推廣合同
- 二零二五年度木材行業(yè)信息化建設(shè)與數(shù)據(jù)服務(wù)合同2篇
- 鍍錫平板軋材項(xiàng)目可行性研究報(bào)告建議書申請(qǐng)備案
- 2020-2025年中國(guó)半導(dǎo)體激光治療機(jī)行業(yè)市場(chǎng)運(yùn)營(yíng)現(xiàn)狀及投資戰(zhàn)略咨詢報(bào)告
- 貴陽(yáng)2025年租賃合同含租賃雙方權(quán)利義務(wù)及爭(zhēng)議解決機(jī)制2篇
- 2025年度文化創(chuàng)意產(chǎn)業(yè)知識(shí)產(chǎn)權(quán)運(yùn)營(yíng)框架協(xié)議
- 二零二五年度道路工程施工合同糾紛處理協(xié)議
- 二零二五年度綠色食品連鎖店進(jìn)貨合同電子版
- 二零二五年度2025年度生物制藥行業(yè)研究員聘用協(xié)議
- 2025年長(zhǎng)沙穗城軌道交通有限公司招聘筆試參考題庫(kù)含答案解析
- 人教版物理八年級(jí)下冊(cè) 專項(xiàng)訓(xùn)練卷 (一)力、運(yùn)動(dòng)和力(含答案)
- 山東省房屋市政工程安全監(jiān)督機(jī)構(gòu)人員業(yè)務(wù)能力考試題庫(kù)-中(多選題)
- 重慶市2023-2024學(xué)年七年級(jí)上學(xué)期期末考試數(shù)學(xué)試題(含答案)
- 2024年中考語(yǔ)文滿分作文6篇(含題目)
- 北師大版 2024-2025學(xué)年四年級(jí)數(shù)學(xué)上冊(cè)典型例題系列第三單元:行程問(wèn)題“拓展型”專項(xiàng)練習(xí)(原卷版+解析)
- 2023年譯林版英語(yǔ)五年級(jí)下冊(cè)Units-1-2單元測(cè)試卷-含答案
- 施工管理中的文檔管理方法與要求
- DL∕T 547-2020 電力系統(tǒng)光纖通信運(yùn)行管理規(guī)程
- 種子輪投資協(xié)議
- 執(zhí)行依據(jù)主文范文(通用4篇)
評(píng)論
0/150
提交評(píng)論