深入類和對象MJLIU市公開課一等獎省賽課獲獎課件_第1頁
深入類和對象MJLIU市公開課一等獎省賽課獲獎課件_第2頁
深入類和對象MJLIU市公開課一等獎省賽課獲獎課件_第3頁
深入類和對象MJLIU市公開課一等獎省賽課獲獎課件_第4頁
深入類和對象MJLIU市公開課一等獎省賽課獲獎課件_第5頁
已閱讀5頁,還剩46頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

C++程序設計與實踐第六章深入類和對象電子科技大學信息與軟件工程學院劉夢娟深入類和對象MJLIU第1頁第六章深入類和對象本章關鍵點結構函數(shù)。結構函數(shù)用于自動地初始化類對象狀態(tài)和申請資源。結構函數(shù)能夠重載,以適應不一樣初始化要求。析構函數(shù)。在對象銷毀時自動調(diào)用,釋放對象占據(jù)資源。一個類只能擁有一個析構函數(shù)。復制結構函數(shù)。復制結構函數(shù)是一個帶有自己類型(常量)引用結構函數(shù)。用于從已存在對象中依據(jù)規(guī)則復制數(shù)據(jù)。this指針。每個對象都擁有一個指向自己指針,它用關鍵字this表示。不過,類靜態(tài)組員函數(shù)沒有this指針。友元。一個類友元能夠訪問該類全部組員。但這只是基于效率考慮。應該慎用友元深入類和對象MJLIU第2頁5、6章基本目標掌握類和對象定義方法;掌握結構函數(shù)和析構函數(shù)實現(xiàn)方法;掌握使用對象、對象指針和對象引用作為函數(shù)參數(shù)方法;掌握類對象作為數(shù)據(jù)組員使用方法;掌握靜態(tài)數(shù)據(jù)組員和靜態(tài)組員函數(shù)使用方法;了解友元概念和掌握友元使用方法。深入類和對象MJLIU第3頁類和對象定義1、類和對象定義方法2、組員定義:數(shù)據(jù)組員、組員函數(shù)3、組員訪問機制class類名{private://定義私有段組員,私有段數(shù)據(jù)和函數(shù)定義;protected://定義保護段組員,保護段數(shù)據(jù)和函數(shù)定義;public://定義公有段組員公有段數(shù)據(jù)和函數(shù)定義;};類名對象名;(5_1.cpp)深入類和對象MJLIU第4頁靜態(tài)組員靜態(tài)數(shù)據(jù)組員:全部對象共享一個靜態(tài)數(shù)據(jù)組員;矩形計數(shù)器例子靜態(tài)數(shù)據(jù)組員定義:靜態(tài)數(shù)據(jù)組員屬于類,而不是對象!靜態(tài)組員函數(shù)static

類型變量(5_2.cpp,5_3.cpp,5_4.cpp)深入類和對象MJLIU第5頁結構函數(shù)結構函數(shù):實現(xiàn)對象自動初始化結構函數(shù)定義結構函數(shù)參數(shù)結構函數(shù)默認參數(shù)結構函數(shù)初始化列表class類名{public:

類名(參數(shù)列表);//結構函數(shù)申明};(5_6.cpp)深入類和對象MJLIU第6頁復制結構函數(shù)復制結構函數(shù)定義復制結構函數(shù)形式化定義為:class類名{public:

類名(const類名&[,otherparameters]);//copyconstructor};深入類和對象MJLIU第7頁何處會調(diào)用復制結構函數(shù)1.顯式定義復制對象Rectangler1;Rectangler2(r1);//callcopyconstructorofr2Rectangler3=r2;//callcopyconstructorofr32.實參和形參結合

如例中rect和r結合時,將會調(diào)用形參rect復制結構函數(shù)來復制實參對象r;3.函數(shù)返回值對象(非指針和引用)

如例中f()返回一個暫時對象,這個暫時對象就是用其復制結構函數(shù)從形參rect復制而來。這個暫時對象是匿名,而且被視為常量對象。(5_7.cpp)深入類和對象MJLIU第8頁課堂練習1、完成point類定義,定義一個點(x,y),寫出結構函數(shù)和復制結構函數(shù)實現(xiàn)

classPoint//Point類申明{public://外部接口Point(intxx=0,intyy=0){X=xx;Y=yy;}//結構函數(shù)Point(Point&p);//拷貝結構函數(shù)intGetX(){returnX;}intGetY(){returnY;}private://私有數(shù)據(jù)intX,Y;};深入類和對象MJLIU第9頁課題練習//組員函數(shù)實現(xiàn)Point::Point(Point&p){X=p.X;Y=p.Y;cout<<"拷貝結構函數(shù)被調(diào)用"<<endl;}//形參為Point類對象函數(shù)voidfun1(Pointp){cout<<p.GetX()<<endl;}深入類和對象MJLIU第10頁考查點:復制結構函數(shù)//返回值為Point類對象函數(shù)Pointfun2(){PointA(1,2);returnA;}voidmain(){PointA(4,5);//第一個對象APointB(A);//情況一,用A初始化B。第一次調(diào)用拷貝結構函數(shù)cout<<B.GetX()<<endl;fun1(B);//情況二,對象B作為fun1實參。第二次調(diào)用拷貝結構函數(shù)B=fun2();//情況三,函數(shù)返回值是類對象,函數(shù)返回時,調(diào)用拷貝結構函數(shù)cout<<B.GetX()<<endl;}(5_8.cpp)深入類和對象MJLIU第11頁課堂練習:組合類類組員中是其它類對象任意給出兩個點位置,計算兩個點組成線段長度。(5_9.cpp)難點:注意Point對象創(chuàng)建次序深入類和對象MJLIU第12頁淺復制和深復制考慮為類List設計復制結構函數(shù)List::List(constList&s):head(s.head),tail(s.tail){}這種僅將類對象本身占據(jù)內(nèi)存復制到另一個對象內(nèi)存中過程稱為“淺復制”深入類和對象MJLIU第13頁淺復制風險淺復制可能帶來潛在危險。假設有以下代碼:voidf(){ Listlist1,list2(list1);}提問:1.哪個對象首先被析構?2.今后會發(fā)生什么情況?深入類和對象MJLIU第14頁List1和List2對象析構情況headList1tailNULLheadList2tail??????深入類和對象MJLIU第15頁深復制處理方案:將鏈表整體復制到目標對象。這就是“深復制”思想,即在目標對象中為源對象全部資源制作一個副本。List::List(constList&s){ head=tail=NULL;

Node*p=s.head; while(p!=NULL) {

push_back(p->quad); p=p->next; }}能夠在結構函數(shù)中調(diào)用其它確定組員函數(shù)。深入類和對象MJLIU第16頁深復制示意List1headtailNULLList2headtailNULL深入類和對象MJLIU第17頁禁止復制在一些尤其應用中,我們編寫List類可能只會產(chǎn)生一個實例。這么一來,List類復制結構函數(shù)實際上是沒有用處。在這種情況下,應該考慮禁止復制發(fā)生深入類和對象MJLIU第18頁禁止復制可能會想到這么方法:不為List類提供復制結構函數(shù)。提問:1.這么做行得通嗎?

2.那么將復制結構函數(shù)放到private段中怎樣?1.必定不行。因為編譯器會為類合成一個默認復制結構函數(shù)。2.也行不通。即使常規(guī)路徑復制嘗試會被編譯器拒絕,但該類友元能夠引發(fā)私有復制結構函數(shù)正當調(diào)用。深入類和對象MJLIU第19頁禁止復制最徹底做法就是在private段中申明一個復制結構函數(shù),但不給出定義。比如:classList{private: List(constList&);//declaretiononly //othermembers};只申明而不定義會“騙過”編譯器。但假如不小心調(diào)用了這種僅有申明私有復制結構函數(shù)調(diào)用,將會產(chǎn)生一個鏈接錯誤。深入類和對象MJLIU第20頁6.3對象創(chuàng)建和初始化對象創(chuàng)建和釋放1)命名自動對象voidf(inta){ Rectangler1; //r1生命期到f函數(shù)返回 Rectangler2; //r2生命期到f函數(shù)返回

if(a>0) { Rectangler3; //r3生命期到if語句結束 … } Rectangler4; //r4生命期到f函數(shù)返回 …}若調(diào)用函數(shù)f,則調(diào)用結構函數(shù)次序是:r1、r2、r3、f4;調(diào)用析構函數(shù)次序是:r3、r4、r2、r1。深入類和對象MJLIU第21頁6.3對象創(chuàng)建和初始化2)匿名自動對象設有以下代碼:Rectangleg(){ returnRectangle(10,20);

}在函數(shù)h()return語句中,函數(shù)標識法引發(fā)了Rectangle類結構函數(shù)調(diào)用,從而產(chǎn)生一個匿名暫時對象。在正常情況下,編譯器將這個匿名暫時對象視為常量,所以它只能作為右值對待。普通地,函數(shù)返回匿名對象會馬上在函數(shù)調(diào)用點被賦值到別對象當中。比如:voidh(){ Rectanglert=g();//OK g();//ill-formed}深入類和對象MJLIU第22頁6.3對象創(chuàng)建和初始化3)自由對象(動態(tài)對象)自由對象經(jīng)過使用new運算符來創(chuàng)建。產(chǎn)生對象擁有長至整個程序運行期生命周期。使用new來創(chuàng)建對象,實際上還是調(diào)用該類結構函數(shù)來創(chuàng)建對象。假如結構函數(shù)有參數(shù),也必須給出實參。當該對象完成使命后,應該馬上使用delete釋放來對象(實際上調(diào)用析構函數(shù))。一旦對象被釋放后,該對象就不能再被使用。比如:voidh(){ Rectangle*p; p=newRectangle(10,20);//callconstructor deletep;//calldestructor}假如沒有顯式釋放自由創(chuàng)建對象,那么該對象將不會自動消失,因為C++沒有自動垃圾回收機制;而且,自由對象往往會因為沒有別指針指向而再也無法訪問,成為孤懸對象。不能使用C格調(diào)malloc()和free()來創(chuàng)建和釋放對象,因為這兩個函數(shù)不會引發(fā)結構函數(shù)和析構函數(shù)調(diào)用。深入類和對象MJLIU第23頁對象初始化1)C格調(diào)初始值列表:聚集初始化inta[5]={1,2,3,4,5};

classconf{public:stringmonth;int year;stringcity;}cpp[]={"Nov", , "SantaFe","Oct", , "Denver","Nov", , "Tyngsboro","April", , "SanFrancisco"};在C++中,以下兩種類型對象被稱為“聚集(aggregate)”:數(shù)組沒有用戶自定義結構函數(shù)、沒有private或protected非靜態(tài)組員、沒有基類、沒有虛函數(shù)類(包含結構體)深入類和對象MJLIU第24頁對象初始化2)復制復制初始化主要施加在類對象上。實際上,復制過程是引發(fā)類對象某個版本結構函數(shù)調(diào)用。有三種方式能夠引發(fā)類對象結構函數(shù)調(diào)用:結構函數(shù)沒有參數(shù),或全部參數(shù)都可缺省,采取以下語法類名對象;結構函數(shù)只有一個參數(shù),能夠采取直接初始化方式:類名對象(參數(shù));

也能夠采取復制初始化方式:類名對象=參數(shù);結構函數(shù)有多于一個參數(shù),采取直接初始化方式:類名對象(參數(shù)列表);深入類和對象MJLIU第25頁復制直接初始化方式僅簡單地引發(fā)了某個匹配版本結構函數(shù)調(diào)用;而復制初始化即使也會引發(fā)結構函數(shù)調(diào)用,但其過程卻可能比較復雜:假如參數(shù)是同類一個對象,那么就會調(diào)用該類復制結構函數(shù);假如參數(shù)不是同類對象,那么可能發(fā)生情況是以下之一:假如參數(shù)類重載了到指定類類型轉換運算符,那么該轉換函數(shù)將被調(diào)用,產(chǎn)生一個指定類類型暫時對象,今后左值對象復制結構函數(shù)會被調(diào)用;不然,左值對象某個結構函數(shù)將發(fā)揮類型轉換功效,產(chǎn)生一個暫時對象,然后調(diào)用左值對象復制結構函數(shù)。Rectangler1(30,40);//簡單地調(diào)用結構函數(shù)Rectangler2;//用默認參數(shù)調(diào)用結構函數(shù)Rectangler3(30);//一樣用默認參數(shù)調(diào)用結構函數(shù)Rectangler4=r1;//調(diào)用r4復制結構函數(shù)Rectangler5(r4);//調(diào)用r5復制結構函數(shù)Rectangler6=Rectangle(30,40);//顯式產(chǎn)生一個暫時對象,然后再調(diào)用r6復制結構函數(shù)Rectangler7=30;//等價于Rectangler7=Rectangle(30)。先用結構函數(shù)完成類型轉換,生成暫時對象,再復制進r7Rectangler8=Square(30);//類Square必須重載從本類到Rectangle類類型轉換函數(shù),不然這個初始化將會失敗深入類和對象MJLIU第26頁6.4對象和指針6.4.1this指針問題:組員函數(shù)怎樣知道自己是被哪個對象調(diào)用呢?this指針this是一個C++關鍵字隱含存在于任一個非靜態(tài)組員函數(shù)中,不能被顯式申明設有以下對象定義:Rectanglerect;那么,對象rect全部非靜態(tài)組員函數(shù)里this指針能夠形象地表示為(但不能顯式申明):Rectangle*constthis=▭組員函數(shù)doubleRectangle::area(){ returnwidth*height;};將被編譯器改造為:doubleRectangle::area(Rectangle*constthis){ returnthis->width*this->height;};this指針只能出現(xiàn)在類非靜態(tài)組員函數(shù)中,而且慣用于需要自引用地方。Rectangle&Rectangle::me(){ return*this;};類靜態(tài)組員函數(shù)沒有this指針。這符合“靜態(tài)組員屬于類而不屬于對象”規(guī)則。深入類和對象MJLIU第27頁6.4對象和指針6.4.2指向類對象指針語法:類類型*指針名;定以后,經(jīng)過使用&和->運算符訪問對象組員voidfun(){ Rectanglerect;

Rectangle*pRect=&rect

pRect->area(); //deletepRect;

pRect=newRectangle pRect->area(); deletepRect;}自動對象不能用delete運算符深入類和對象MJLIU第28頁6.4.3指向類組員指針1.類組員指針定義指向類組員指針不屬于類,它們定義在類外部,其語法為:類型名類名::*指針;

類型名(類名::*指針)(參數(shù)表);classX{private: inta;

public: intb; floatc;

intf(); intg(); inth(int);};如有定義intX::*ptr;int(X::*fptr)();那么以上兩個指針能夠指向類X那些組員?ptr能夠指向b,但不能指向a(因其私有)和c(類型不一樣);fptr能夠指向f()或g(),但不能指向h()(類型不一樣)。深入類和對象MJLIU第29頁6.4對象和指針2.類組員指針使用在使用類組員指針之前,必須對其進行初始化。給指向類組員指針初始化工作能夠發(fā)生在定義類對象之前。下面代碼完成了指針與類組員綁定:ptr=&X::b;fptr=&X::f;深入類和對象MJLIU第30頁6.4對象和指針因為沒有對象產(chǎn)生,所以ptr和fptr將不知道自己作用在哪個對象上,因而這種初始化工作只是形式上關系確定。要使指針發(fā)揮作用,必須定義對象,然后使用組員選擇運算符.*或->*來完成操作。voidfun(){XObj;X*pObj=&Obj;

ptr=&X::b;fptr=&X::f;

Obj.*ptr=2;//Obj.b=2++pObj->*ptr;//++Obj.b

(Obj.*fptr)();//callObj.f();(pObj->*fptr)();

fptr=&X::g;(Obj.*fptr)();//callObj.g()}代碼Obj.*fptr()是錯誤。因為這會首先解釋為Obj.*(fptr())這就意味著,fptr是個函數(shù),并將它返回值綁定到組員選擇運算符.*上,這顯然是不正確。深入類和對象MJLIU第31頁6.5友元關系一個對象私有數(shù)據(jù),只能經(jīng)過組員函數(shù)進行訪問,這是一堵不透明墻。這種限制性給這么一個情況造成了困擾:類一些組員標準上應該是私有,但卻需要在外部頻繁訪問他們友元(friend)機制一個類友元能夠是一個外部函數(shù),也能夠是一個類。它們即使不是該類組員,但卻能訪問該類任何組員。這顯然提升了訪問效率友元分類友元函數(shù)友元類深入類和對象MJLIU第32頁6.5.1友元函數(shù)語法:class類名{

//othermembers;

friend函數(shù)申明;};比如:intf();classA{friendintf();}友元申明必須放在類定義中,但放在哪個段中無關緊要。classRectangle//簡化版{private: int width,height; //othermemberspublic: friendintperimeter(constRectangle&r);};

intperimeter(constRectangle&r){ return(r.width+r.height)*2;}在友元函數(shù)中直接訪問類私有組員深入類和對象MJLIU第33頁6.5.1友元函數(shù)一旦申明了類友元,那么該類作用域就對友元開放。也就是說,類全部組員對友元都是可見、可訪問友元作用范圍僅限在直接申明它類中。友元不能逾越嵌套類界限而訪問到外部類,除非友元同時也被顯式申明為外部類友元比如:classC{ friendintf();};classA{ classB{friendintf();} CobjC;};函數(shù)f()僅僅是類B和類C友元,而非類A友元。深入類和對象MJLIU第34頁6.5.1友元函數(shù)全局友元函數(shù)不屬于任何類,所以全局友元函數(shù)沒有this指針。除了全局友元函數(shù)外,一個類組員函數(shù)也能夠成為其它類友元。classRectangle;//forwarddeclarationclassCalculator{public: intperimeter(constRectangle&r);};

classRectangle//簡化版{private: int width,height; //othermemberspublic:

friendintCalculator::perimeter(constRectangle&r);};

intCalculator::perimeter(constRectangle&r){ return(r.width+r.height)*2;}必須前向申明深入類和對象MJLIU第35頁6.5.2友元類假如將一個類A申明為類B友元類,那么,類A全部組員函數(shù)都成為類B友元函數(shù)。classPainter;

classRectangle//簡化版{private: int width,height; //othermemberspublic:

friendclassPainter;};

classPainter{public:voiddraw(constRectangle&r){cout<<r.width<<','<<r.height<<endl;}};深入類和對象MJLIU第36頁6.5.3友元關系特征友元機制主要性在于兩個方面。首先,某個函數(shù)能夠是多個類友元,使用友元函數(shù)能提升效率,使得表示簡練、清楚。其次,在運算符重載和泛型編程一些場所需要使用友元。友元含有以下特征:非傳遞性。即A是B友元,B是C友元,但A不一定是C友元(除非將A申明為C友元);非對稱性。即A是B友元,但B不一定是A友元(除非將B申明為A友元)。友元函數(shù)例子:計算兩個點之間距離參見例子5_12.cpp深入類和對象MJLIU第37頁6.6與類和對象相關問題6.6.1對象數(shù)組對象數(shù)組每個數(shù)組元素都是一個對象需要屢次調(diào)用結構函數(shù)釋放對象數(shù)組時,也需要屢次調(diào)用析構函數(shù)比如:RectanglerectArr[10];參見例子5_13.cpp深入類和對象MJLIU第38頁6.6與類和對象相關問題要創(chuàng)建一個類對象數(shù)組,該類結構函數(shù)必須滿足以下幾個條件之一:沒有顯式定義結構函數(shù);有顯式定義結構函數(shù),但其中有一個結構函數(shù)沒有參數(shù);有顯式定義結構函數(shù),但其中有一個結構函數(shù)全部參數(shù)都能夠默認;除了直接定義對象數(shù)組外,還能夠使用new運算符來動態(tài)創(chuàng)建對象數(shù)組。比如:Rectangle*p=newRectangle[3];而在使用完成后,能夠使用delete運算符來釋放整個數(shù)組。比如:delete[]p;深入類和對象MJLIU第39頁6.6.2類對象做為函數(shù)參數(shù)和返回值對象作為函數(shù)參數(shù)voidf(Rectangler);//值參數(shù)【復制結構函數(shù)】voidg(Recangle*r);//指針參數(shù)voidh(Rectangle&r);//引用參數(shù)對象值做參數(shù),對形參對象任何修改都不影響用作實參對象。對象引用做參數(shù),對形參對象任何修改就是直接對實參對象修改。普通情況下,選擇常量引用作為參數(shù)是一個非常好選擇。對象指針做參數(shù),對它指向對象作任何修改就是間接對實參對象修改;而修改參數(shù)本身將會造成參數(shù)指針指向別對象,對實參對象沒有任何影響。深入類和對象MJLIU第40頁6.6.2類對象做為函數(shù)參數(shù)和返回值2.函數(shù)返回對象Rectanglef(Rectangler){returnr;}//返回值Rectangle*g(Recangle*r){returnr;}//返回指針Rectangle&h(Rectangle&r){returnr;}//返回引用函數(shù)f()返回對象r值,這要產(chǎn)生一個匿名暫時常量對象g()返回對象指針,也就是返回對象地址,不會引發(fā)結構函數(shù)調(diào)用h()返回對象引用,就是返回對象本身,能夠作為左值使用。需要注意是,在函數(shù)返回對象指針或引用時,被指向或被引用對象必須含有超出函數(shù)作用域生命期。例函數(shù):Rectangle&f(Rectangler){returnr;}會出現(xiàn)什么問題?深入類和對象MJLIU第41頁6.6.3常量對象const關鍵字能夠約束普通變量,也能夠約束一個對象,使之成為常量對象。比如:constRectanglerect(3,4);這么一來,對象rect全部屬性都是不可修改,除非某個屬性被說明成是mutable常量對象兩種使用情形:函數(shù)返回對象值這一情況。這個返回對象被編譯器自動約束成為常量對象常量對象作為函數(shù)參數(shù)與無約束對象一樣,能夠調(diào)用常量對象組員函數(shù)來完成某項操作。但這可能帶來潛在錯誤:這個組員函數(shù)可能會修改對象屬性易變常對象不能被更新深入類和對象MJLIU第42頁6.6.4常組員函數(shù)類一些組員函數(shù)只是讀取屬性而不修改它們。這么,能夠將這么組員說明成是常組員。比如:classRectangle//簡化版{private: int width,height; //othermemberspublic: doublearea()const{returnwidth*height;}};關鍵字const將組員函數(shù)area()this指針和它指向對象約束成為常量,所以在其內(nèi)部任何試圖改變對象狀態(tài)操作都是非法。在常組員函數(shù)中不能調(diào)用非常組員函數(shù),因為那些函數(shù)有可能改變對象狀態(tài)。假如在類內(nèi)申明常組員函數(shù)而在類外定義它,那么二者申明必須完全一致。比如:classRectangle//簡化版{private: int width,height; //othermemberspublic: doublearea()const;};

doubleRectangle::area()const

{returnwidth*height;}深入類和對象MJLIU第43頁6.6.5嵌套類假如類A只為類B提供服務,那么A最好成為B內(nèi)部類。這里,類A稱為類B“嵌套類(nestedclass)”,而類B是類A“包圍類”。1.嵌套類定義classRectangle{public: stringname;

structSize { intwidth,height; v

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論