




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第9章類的高級局部皮德常南京航空航天大學計算機科學與技術學院1主要內容9.1靜態成員9.2友元9.3對象賦值問題9.4拷貝構造函數9.5運算符重載9.6對象組合29.1靜態成員例:一個學生類,定義其對象張三、李四,他們分別維護著類成員的一份副本〔學號、姓名、籍貫等〕。如果要統計一個班學生總數?用類外的變量記錄,違背了數據封裝。用類的一個數據成員記錄,導致多個副本,不僅冗余,而且勢必造成數據不一致。39.1.1靜態數據成員1.用關鍵字static聲明;2.同一個類中的所有對象都共享該變量;3.必須在類外定義和初始化,用(::)來指明所屬的類。4.靜態變量不依賴于對象而存在,無論是否認義該類的對象,這種類型的變量都存在。靜態數據成員實際上是在類外定義的一個變量,它的生存期和整個程序的生存期一樣,在定義對象之前,靜態數據成員就已經存在。4classStaticDemo{staticintx;
inty;public:voidputx(inta){x=a; }voidputy(intb){y=b; }intgetx(){returnx; }intgety(){returny; }};intStaticDemo::x; //靜態變量x將被StaticDemo類的所有對象共享,例如:StaticDemoobj1,obj2;obj1.putx(5);obj1.puty(l0);obj2.puty(20);cout<<"x:"<<obj1.getx()<<""<<obj2.getx()<<endl;cout<<"y:"<<obj1.gety()<<""<<obj2.gety()<<endl;理解它!59.1.2靜態函數成員靜態函數成員是類中的一個函數,有static修飾。靜態函數成員和靜態數據成員類似,在對象生成之前也已經存在。這就是說在對象產生之前,靜態的函數成員就能訪問其它靜態成員。類外代碼可以使用類名和作用域操作符來調用靜態成員函數。靜態成員函數只能引用屬于該類的靜態數據成員或靜態成員函數。見例【例9-2】。6//budget2.h文件的內容。classBudget{ staticfloatcorpBudget; floatdivBudget;public: Budget(){divBudget=0;} voidaddBudget(floatb) { divBudget+=b; corpBudget+=divBudget; }
staticvoidmainOffice(float); floatgetDivBudget(){returndivBudget;} floatgetCorpBudget(){returncorpBudget;}};7//Contentsofbudget2.cpp#include"budget2.h"floatBudget::corpBudget=0; //Definitionofstaticmemberfunction.
voidBudget::mainOffice(floatmoffice){ corpBudget+=moffice;}8//主程序pr9-2.cpp的內容#include"budget2.h“voidmain(){ floatamount; inti; floatbud; cout<<"Entermainoffice'sbudgetrequest:"; cin>>amount;
Budget::mainOffice(amount); Budgetdivisions[4];9for(i=0;i<4;i++){ cout<<"EnterthebudgetforDivision"; cout<<(i+1)<<""; cin>>bud; divisions[i].addBudget(bud);}cout<<"\nHerearethedivisionbudget:\n";for(i=0;i<4;i++){ cout<<"\tDivision"<<(i+1)<<"\t$"; cout<<divisions[i].getDivBudget()<<endl;}10 cout<<"\tTotalRequests:"; cout<<divisions[0].getCorpBudget()<<endl;}1.對于靜態的函數成員,是通過類名和作用域分辨符調用的。2.也可以采用對象點的方式調用budget2.h
budget2.cpp9-2.cpp119.2友元函數引入友元的原因?1.友元函數不是類中的函數成員,但它和類的函數成員一樣,可以訪問類中定義的私有成員。2.友元函數可以是一個外部函數,也可以是另外一個類的函數成員。3.將某個函數聲明為一個類的友元方式,前面加friend。12【例9-3】求兩個點之間的距離。classPoint{ intxPos,yPos;public: Point(intxx=0,intyy=0) {xPos=xx;yPos=yy;} intGetXPos(){returnxPos;} intGetYPos(){returnyPos;}
frienddoubleDistance(Point&a,Point&b);};9.2.1外部函數作為類的友元13doubleDistance(Point&a,Point&b){
doubledx=a.xPos-b.xPos; doubledy=a.yPos-b.yPos; returnsqrt(dx*dx+dy*dy);}voidmain(){Pointp1(3,5),p2(4,6);cout<<Distance(p1,p2)<<endl;}9-3.cpp不采用友元如何解決?14其他類的成員函數聲明為一個類的友元函數,這個成員函數也稱為友元成員。友元成員不僅可以訪問自己所在類對象中的私有成員和公有成員,還可以訪問friend聲明語句所在類對象中的私有成員和公有成員,這樣能使兩個類相互合作完成某一任務。例:將Aux類的函數addBudget聲明為Budget類的友元函數。9.2.2類的成員函數作為另外一個類的友元15classBudget;//對Budget類超前使用說明classAux //Aux類的定義{private:floatauxBudget;public:Aux(){auxBudget=0;}voidaddBudget(float,Budget&);floatgetDivBudget(){returnauxBudget;}};16classBudget//Budgetclassdeclaration{staticfloatcorpBudget;floatdivBudget;public:Budget(){divBudget=0;}voidaddBudget(floatB)
{divBudget+=B;corpBudget+=divBudget;}floatgetDivBudget(){returndivBudget;}floatgetCorpBudget(){returncorpBudget;}
staticvoidmainOffice(float);
friendvoidAux::addBudget(float,Budget&);};17//Contentsofbudget3.cpp#include"budget3.h" //DefinitionofstaticmemberofBudgetclassfloatBudget::corpBudget=0;//DefinitionofstaticmemberfunctionmainOffice.
voidBudget::mainOffice(floatmoffice){ corpBudget+=moffice;}18//Contentsofauxi1.cpp#include"auxi1.h"#include"budget3.h"http://DefinitionofmemberfunctionmainOffice.voidAux::addBudget(floatb,Budget&div){ auxBudget+=b;
div.corpBudget+=auxBudget;}AttentionPlz19//Contentsofmainprogram#include"budget3.h“voidmain(){ floatamount; inti; floatbud; cout<<"Enterthemainoffice'sbudget:"; cin>>amount;
Budget::mainOffice(amount); Budgetdivisions[4];AuxauxOffices[4];20for(i=0;i<4;i++){cout<<"Enterthebudgetrequestfordivision"; cout<<(i+1)<<":"; cin>>bud; divisions[i].addBudget(bud); cout<<"Enterthebudgetrequestfordivision"; cout<<(i+1)<<"'sauxiliaryoffice:"; cin>>bud; auxOffices[i].addBudget(bud,divisions[i]);}21cout<<"Herearethedivisionbudgetrequests:\n";for(i=0;i<4;i++) {cout<<"\tDivision"<<(i+1)<<"\t\t\t"; cout<<setw(7); cout<<divisions[i].getDivBudget()<<endl; cout<<"\tAuxilaryOfficeofDivision"<<(i+1); cout<<"\t"; cout<<auxOffices[i].getDivBudget()<<endl;}cout<<"\tTotalRequests(includingmainoffice):";cout<<divisions[0].getCorpBudget()<<endl;}auxi1.hbudget3.hauxi1.cppbudget3.cpp9-3.cpp229.2.3一個類作為另外一個類的友元假設一個類為另一個類的友元,那么此類的所有成員都能訪問對方類的私有成員。classA{intx;
friendclassB;public:voidDisplay(){cout<<x<<endl;}};classB{
Aa;public:voidSet(inti){a.x
=i;}voidDisplay(){a.Display();}};不好的方法,勿模仿239.3對象賦值問題采用賦值運算符“=”可以將一個對象賦值給另外一個對象,或者采用一個對象初始化另外一個對象。在缺省情況下,這兩個操作執行的是對象成員之間的拷貝,也稱為按位拷貝或淺拷貝。
【例9-5】淺拷貝應用舉例。.24classRectangle{floatwidth,length,area;voidcalcArea(){area=width*length;}public:voidsetData(floatw,floatl){ width=w;length=l;calcArea();}floatgetWidth(){returnwidth;}floatgetLength(){returnlength;}floatgetArea(){returnarea;}};25voidmain(){ Rectanglebox1,box2; box1.setData(10,20); box2.setData(5,10); cout<<"\nBoxl'sArea:"<<box1.getArea(); cout<<"\nBox2'sArea:"<<box2.getArea(); box2=box1; //對象賦值 cout<<"\nBoxl'sArea:"<<box1.getArea(); cout<<"\nBox2'sArea:"<<box2.getArea();}9-5.cpp269.3對象賦值問題(continued)當采用一個對象初始化另一個對象時,對象成員之間的賦值也是按位拷貝。賦值和初始化的區別:賦值出現在兩個對象都已經存在的情況下,而初始化出現在創立對象時,例如: Rectanglebox1; box1.setData(100,50); Rectanglebox2=box1;//initialization279.4拷貝構造函數拷貝構造函數是一個特殊的構造函數,當定義一個對象并采用同類型的另外一個對象初始化時,將自動調用拷貝構造函數。通常,采用缺省的按位拷貝操作也能正確地實現賦值,但在某些情況下不能正確執行。Example:
28classPersonInfo{ char*name; intage;public: PersonInfo(char*n,inta) { name=newchar[strlen(n)+1]; strcpy(name,n); age=a; }
~PersonInfo(){delete[]name;} char*getName(){returnname;} intgetAge(){returnage;}};PersonInfoperson1("Jones",20);PersonInfoperson2=person1;//將產生???291.解決的方法:定義拷貝構造函數。2.拷貝構造函數是一個特殊的構造函數,當采用一個對象初始化另一個對象時,將自動調用該函數。PersonInfo(PersonInfo&obj){ name=newchar[strlen(obj.name)+1]; strcpy(name,); age=obj.age;}拷貝構造函數的參數代表“=”運算符右邊的對象:
PersonInfoperson2=person1;30進一步演化:UsingconstParametersPersonInfo(constPersonInfo&obj){ name=newchar[strlen(obj.name)+1]; strcpy(name,); age=obj.age;}319.4.1缺省的拷貝構造函數如果一個類沒有定義拷貝構造函數,C++將為其創立一個缺省的拷貝構造函數。缺省的拷貝構造函數的功能就是按位賦值。321.用對象初始化同類的另一個對象。例如:
PersonInfost1("ZhangSan",20);
PersonInfost2(st1),st3=st1;9.4.2調用拷貝構造函數的情況Ex9-a.cpp332.如果函數的形參是對象,當進行參數傳遞時將調用拷貝構造函數。
voidchangePerson(PersonInfop){//…}
voidmain(){PersonInfost1("Susan",20);changePerson(st1); }思考:為什么拷貝構造函數的參數一定是個引用,而不是對象?Ex9-b.cpp343.如果函數的返回值是對象,函數執行結束時,將調用拷貝構造函數對無名臨時對象初始化。
classPersonInfo{public:PersonInfo(){cout<<"調用構造函數\n";}PersonInfo(PersonInfo&obj){cout<<"調用拷貝\n";}~PersonInfo(){cout<<"調用析構函數\n";}};
PersonInfogetPerson(){PersonInfoperson;returnperson;//函數的返回值是對象}
voidmain(){PersonInfostudent;student=getPerson();}35注意:VC2005版本有問題,VC6正確。Ex9-c.cpp36如果函數返回值是對象,要考慮return語句的效率。例如: returnstring(s1+s2);表示“創立一個無名的臨時對象并且將它返回”與“先創立一個局部對象temp并返回”不等價: stringtemp(s1+s2); returntemp;379.4.4編譯器的一個紕漏classInvoiceItem{public: InvoiceItem(intsize=51)
{ cout<<"調用缺省構造函數!\n"; } InvoiceItem(char*d)
{ cout<<"調用一個參數的構造函數!\n";} InvoiceItem(char*d,intu)
{ cout<<"調用兩個參數的構造函數!\n"; } InvoiceItem(InvoiceItem&obj)
{ cout<<"調用拷貝構造函數!\n"; } ~InvoiceItem()
{ cout<<"調用析構函數!\n"; }};389.4.4編譯器的一個紕漏intmain(){ InvoiceItemInventory[5]={//對象數組
InvoiceItem("鼠標",100), //A行
InvoiceItem("硬盤"), //B行
"主板", //C行
99 //D行
}; return0;}注意:VC2005和VC6都不正確。9-ERROR.cpp399.5運算符重載Example1:The/operatorcanperformtwotypesofdivision:floatingpointandinteger.
Example2: Datetoday(2011,4,28); today.add(5); today+=5;//???409.5.1重載賦值運算符如果對象中有指針成員,采用拷貝構造函數能解決對象初始化問題,但并不能處理對象賦值。Example:假設PersonInfo具有拷貝構造函數:PersonInfoperson1("ZhangSan”,20),person2("John",24);person2=person1;//memberwiseassignment
41Overloadthe=operator:classPersonInfo{char*name;
intage;public: ……
voidoperator=(constPersonInfo&right){ delete[]name; name=newchar[strlen()+1]; strcpy(name,); age=right.age;}};
42operator=函數的參數不一定是常引用,上述聲明優點:(1)效率高。采用引用可以防止參數傳遞時生成對象拷貝,節省了對象初始化和析構的過程。(2)將參數聲明為常引用,可以防止函數無意間修改對象right的內容。(3)符合賦值運算的常識。函數調用:p2.operator=(p1);
p2=p1;p3=p2=p1;//???439.5.2this指針this是一個隱含的內嵌指針,它指向調用成員函數的當前對象。Example:
cout<<person1.getName()<<endl; cout<<person2.getName()<<endl;44//【例9-8】
classPersonInfo{ char*name; intage;public:PersonInfooperator=(constPersonInfo&right){ delete[]name; name=newchar[strlen()+1];strcpy(name,); age=right.age;return*this;}//其他函數略};45voidmain(){PersonInfojim("Jim",20),bob("Bob",21), clone=jim;clone=bob=jim;
//Calloverloaded=operatorcout<<clone.getName()<<"," <<clone.getAge()<<endl;}operator=還有問題嗎?46PersonInfo&operator=(constPersonInfo&right){ //重載運算符“=”的秘笈:
//一、檢查自賦值
if(this==&right)return*this;
//二、釋放原有的內存空間
delete[]name;
//三、分配新的內存空間,并復制內容
name=newchar[strlen()+1];strcpy(name,);age=right.age;
//四、返回本對象的引用
return*this;}9-8.cpp47this指針是以隱含參數的形式傳遞給非靜態的函數成員:
PersonInfo(char*name,intage)
{
this->name=newchar[strlen(name)+1];strcpy(this->name,name);
this->age=age;}489.5.3重載雙目算術運算符引入原因:
Feetincheslength1(3,5),length2(6,3),length3; length3=length1+length2;//等價于
length3=length1.operator+(length2);僅講述如何重載雙目運算符+和-,其它類似。49classFeetInches{ intfeet,inches;voidsimplify();public://其他函數代碼見節 ……FeetInchesoperator+(constFeetInches&);FeetInchesoperator-(constFeetInches&);};50//Overloadedbinary+operator.FeetInchesFeetInches::operator+( constFeetInches&right){ FeetInchestemp; temp.inches=inches+right.inches; temp.feet=feet+right.feet; temp.simplify(); returntemp;}51//Overloadedbinary-operator.FeetInchesFeetInches::operator-( constFeetInches&right){ FeetInchestemp; temp.inches=inches-right.inches; temp.feet=feet-right.feet; temp.simplify(); returntemp;}529.5.3重載雙目算術運算符任何一個雙目算術運算符B被重載以后,當執行二元運算時:Obj1BObj2完全等價于:Obj1.operatorB(Obj2)Ex9-d.cpp539.5.4重載單目算術運算符Example1:
distance2=++distancel;//前置++等價于: distance2=distancel.operator++();Example2:
distance2=distancel++;//后置++等價于: distance2=distancel.operator++(0);54classFeetInches//【例9-9】{ intfeet,inches;voidsimplify();public: ……FeetInchesoperator+(constFeetInches&);FeetInchesoperator-(constFeetInches&);
FeetInches
operator++();FeetInchesoperator++(int);};Dummyparameter55//Overloadedprefix++operator.FeetInchesFeetInches::operator++(){ ++inches; simplify(); return*this;}56 //Overloadedpostfix++operator.FeetInchesFeetInches::operator++(int){ FeetInchestemp(feet,inches); inches++; simplify(); return temp;}Ex9-e.cpp579.5.5重載關系運算符重載關系運算符,實現兩個對象的比較,其中關系運算符函數要返回一個布爾值〔true或false〕:Example:if(distancel<distance2){ ...code...}58classFeetInches{intfeet,inches;voidsimplify();public: ……booloperator>(constFeetInches&);
booloperator<(constFeetInches&);
booloperator==(constFeetInches&);};59//Overloaded>operator.
bool FeetInches::operator>( constFeetInches&right){if(feet>right.feet) returntrue;elseif(feet==right.feet&&inches>right.inches) returntrue;elsereturnfalse;}60//Overloaded<operator.boolFeetInches::operator<( constFeetInches&right){if(feet<right.feet) returntrue;elseif(feet==right.feet&&inches<right.inches) returntrue;else returnfalse;}61//Overloaded==operator.boolFeetInches::operator==( constFeetInches&right){if(feet==right.feet&&inches==right.inches) returntrue;else returnfalse;}Ex9-f.cpp629.5.6重載流操作符<<和>>Example: intvalue; cout<<value; FeetInchesdistance;
cin>>distance;
注意:如果要為FeetInches類重載流插入符<<,那么必須通過友元函數的形式實現函數重載。能否實現?63classFeetInches{intfeet,inches;public: ……friend
ostream&operator<<(ostream&, FeetInches&);friendistream&operator>>(istream&, FeetInches&);};64//Overloaded<<operator.ostream
&operator<<( ostream&strm, FeetInches&obj){ strm<<obj.feet<<"feet," <<obj.inches<<"inches"; return strm;}65//Overloaded>>operator.istream &operator>>( istream&strm, FeetInches&obj){ cout<<"Feet:";strm>>obj.feet; cout<<"Inches:";strm>>obj.inches; return strm;}66
cout<<distancel<<""<<distance2<<endl;等價于如下過程:1.首先調用重載函數<<,執行cout<<distancel,返回cout對象;2.執行cout<<“”,返回值是cout對象;3.以(1)的方式,執行cout<<distance2;4.以(2)的方式,執行表達式中的cout<<endl;Ex9-g.cpp679.5.7重載類型轉換運算符Example: inti=100; floatf=3.14f; i=f; f=i;對于一個對象,通過重載類型轉換函數,可實現類型轉換功能。
68classFeetInches{intfeet,inches;public: …… operatorfloat();
//Truncatestheinchesvalue operatorint(){ returnfeet; }};Noreturntypeisspecifiedinthefunctionheader.SincethefunctionisaFeetInches-to-floatconversionfunction,itwillalwaysreturnafloat.69
//ConvertaFeetInchesobjecttoafloat.
FeetInches::operatorfloat(){ floattemp=feet; temp+=(inches/12.0f); returntemp;}70voidmain(){ FeetInchesdistance; float f; int i; cin>>distance; f=distance; i=distance;}Ex9-h.cpp719.5.8重載[]操作符Example1: stringname="John"; cout<<name[0]; name[0]='a';C++除了支持重載傳統的運算符,還支持重載[]符。這樣就能象操作普通數組一樣操作對象數組。72classIntArray{ int*aptr; intarraySize; voidmemError(); voidsubError();public: IntArray(int); IntArray(constIntArray&); ~IntArray(); intsize(){returnarraySize;} int&operator[](constint&);};why?73//ConstructorforIntArrayclassIntArray::IntArray(ints){ arraySize=s; aptr=newint[s]; if(aptr==0) memError(); for(inti=0;i<arraySize;i++) *(aptr+i)=0;}74//CopyConstructorforIntArrayclass.IntArray::IntArray(constIntArray&obj){ arraySize=obj.arraySize; aptr=newint[arraySize]; if(aptr==0) memError(); for(inti=0;i<arraySize;i++) *(aptr+i)=*(obj.aptr+i);}75//DestructorforIntArrayclass.IntArray::~IntArray(){ if(arraySize>0) delete[]aptr; arraySize=0;}76 //memErrorfunction.voidIntArray::memError(){ cout<<"Cannotallocatememory.\n"; exit(0);} //subErrorfunction.voidIntArray::subError(){ cout
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年嵩山少林武術職業學院高職單招職業技能測試近5年常考版參考題庫含答案解析
- 2025年山東電子職業技術學院高職單招高職單招英語2016-2024歷年頻考點試題含答案解析
- 2025年山東海事職業學院高職單招高職單招英語2016-2024歷年頻考點試題含答案解析
- HSE安全培訓知識課件
- 2025年天津渤海職業技術學院高職單招(數學)歷年真題考點含答案解析
- 2025年天津生物工程職業技術學院高職單招職業技能測試近5年常考版參考題庫含答案解析
- 紙漿班本課程匯報
- 秋天再見課件小班
- DB3204-T 1072-2024 化工園區污染地塊土壤風險管控和修復施工過程環境管理規范
- 老年口腔健康教育
- GB 4053.2-2009固定式鋼梯及平臺安全要求第2部分:鋼斜梯
- GB 14934-2016食品安全國家標準消毒餐(飲)具
- 民本思想課件
- 健身氣功八段錦教案
- 象棋-小學社團活動記錄表
- 邊坡坡度測量記錄表
- 中職 AutoCAD 2018計算機輔助設計項目化教程課程標準
- 功能醫學與健康管理
- HZS75型攪拌站安裝施工方法
- DB13(J)∕T 8377-2020 建筑施工安全管理標準
- 吊裝施工施工組織設計
評論
0/150
提交評論