C++面向?qū)ο蟪绦蛟O(shè)計(杜茂康 第4版)-課件 第6-8章 運算符重載、模板和STL、異常_第1頁
C++面向?qū)ο蟪绦蛟O(shè)計(杜茂康 第4版)-課件 第6-8章 運算符重載、模板和STL、異常_第2頁
C++面向?qū)ο蟪绦蛟O(shè)計(杜茂康 第4版)-課件 第6-8章 運算符重載、模板和STL、異常_第3頁
C++面向?qū)ο蟪绦蛟O(shè)計(杜茂康 第4版)-課件 第6-8章 運算符重載、模板和STL、異常_第4頁
C++面向?qū)ο蟪绦蛟O(shè)計(杜茂康 第4版)-課件 第6-8章 運算符重載、模板和STL、異常_第5頁
已閱讀5頁,還剩275頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第6章運算符重載本章主要教學(xué)內(nèi)容運算符重載的原理、基本原則和實現(xiàn)方法一元運算符重載、二元運算重載運算符重載方式:成員運算符重載、友元運算符重載、普通函數(shù)重載運算的區(qū)別和編程方法重載特殊運算符:++,--,[],=,類型轉(zhuǎn)換運算符輸入、輸出運算符重載仿函數(shù)本章教學(xué)重點運算符重載的基本原則和實現(xiàn)方法以成員函數(shù)和友元方式重載一元運算符和二元運算符重載++、--、[]和類型轉(zhuǎn)換運算符重載輸入輸出運算符重載教學(xué)難點++、--運算符重載(前綴、后綴運算符重載的區(qū)別、參數(shù)和返回類型設(shè)計)輸入、輸出運算符重載二元運算符重載為成員函數(shù)和普通函數(shù)(包括友元)的區(qū)別(對形參的類型轉(zhuǎn)換)第6章

運算符重載本章介紹C++運算符重載的相關(guān)內(nèi)容,包括:以類成員函數(shù)、友元和普通函數(shù)方式進行運算符重載的方法輸入/輸出運算符重載某些特殊運算符(如++、--、[]、()等)重載。6.1運算符重載基礎(chǔ)1、運算符重載的概念運算符重載是C++的一項強大功能。通過重載,可以擴展C++運算符的功能,使它們能夠操作用戶自定義的數(shù)據(jù)類型,增加程序代碼的直觀性和可讀性。C++的運算符對語言預(yù)定義類型是重載的inti=2+3;doublej=2+4.8;floatf=float(3.1)+float(2.0);對于上面的3個加法表達式,C++系統(tǒng)提供了類似于下面形式的運算符重載函數(shù):intoperator+(int,int);doubleoperator+(int,double);floatoperator+(float,float);C++允許程序員通過重載擴展運算符的功能使重載后的運算符能夠?qū)τ脩糇远x的數(shù)據(jù)類型進行運算。比如,設(shè)有復(fù)數(shù)類Complex,其形式如下:classComplex{ doublereal,image;public:......};假設(shè)要實現(xiàn)下面兩個復(fù)數(shù)相加的運算。Complexc1,c2,c3;……c1=c2+c3;6.1運算符重載基礎(chǔ)這條語句是錯誤的,除非用下面的方法重載“+”運算符,為它增加復(fù)數(shù)相加的運算能力:Complexoperator+(Complexc1,Complexc2){……}why?使程序便于編寫和閱讀使程序定義類型與語言內(nèi)建類型更一致how?使用特殊的成員函數(shù)使用自由函數(shù),一般為友元6.1運算符重載基礎(chǔ)運算符重載限制(1)可以重載的運算符預(yù)定義的運算符才能夠被重載,這些運算符如下:+ - * / % ^ & | ~! , = < > <= >= ++ --<< >> == != && || += -= /=%= ^= &= |= *= <<= >>= [] ()-> ->* new new[] delete delete[](2)不能被重載的運算符. .* :: ?:(3)只能被重載為類成員函數(shù)的運算符= [] () ->6.1運算符重載基礎(chǔ)(4)運算符重載過程中的基本原則(限制條件)①不能改變運算符的優(yōu)先級。②不能改變運算符的結(jié)合順序(如+、-、*、/等運算符按照從左到右結(jié)合,這個順序不能改變)。③重載運算符不能使用默認(rèn)參數(shù)。④不能改變運算符所需要的參數(shù)個數(shù)。⑤不能創(chuàng)造新運算符,只能重載系統(tǒng)已有的運算符。⑥不能改變運算符的原有含義。⑦若運算符被重載為類的成員函數(shù),則只能是非靜態(tài)成員函數(shù)。6.1運算符重載基礎(chǔ)3、運算符重載的語法運算符可以非類成員的普通形式重載,運算符的計算結(jié)果是值,因此運算符函數(shù)是要返回值的函數(shù)。其重載的語法形式如下:返回類型operator@(參數(shù)表)其中,operator是C++的保留關(guān)鍵字,表示運算符函數(shù)。@代表要重載的運算符,它可以是前面列舉的可重載運算符中的任何一個。例如,intoperator-(inta,intb){returna

b;}6.1運算符重載基礎(chǔ)3.與類相關(guān)的運算符重載方式(1)編譯器為類生成的默認(rèn)運算符重載函數(shù)賦值運算(=)取類對象地址的運算符(&),成員訪問運算符(如“.”和“->”)。這些運算符不需要重載就可以使用,而其它運算符則其有重載了才能夠應(yīng)用。(2)類運算符重載方式重載為類的非靜態(tài)成員函數(shù)重載為類的友元函數(shù)重載為普通函數(shù)6.1運算符重載基礎(chǔ)非靜態(tài)成員函數(shù)的重載運算符運算符重載為類成員函數(shù)時,其第1個參數(shù)是由編譯器通過this指針隱式傳遞,因此其參數(shù)個數(shù)要比該運算符實際的參數(shù)個數(shù)少一個。例如classComplex{ doublereal,image;public:

Complexoperator+(Complexx){……}

……};Complexa,b,c;a=b+c;b+c調(diào)用了重載運算符+,參數(shù)b傳遞給了隱式參數(shù),而+運算符函數(shù)是隱式參數(shù)的成員函數(shù),語句“a=b+c;”與“a=b.operator+(c);”等價6.1運算符重載基礎(chǔ)友元或普通函數(shù)重載運算符重載為普通函數(shù)或類的友元,參數(shù)個數(shù)就與運算符實際參數(shù)個數(shù)相同。形式如下:classComplex{

…… friendComplexoperator+(Complexa,Complexb); };Complexoperator+(Complexa,Complexb){……}//友元定義Complexoperator-(Complexa,Complexb){……}//普通函數(shù)

友元和普通函數(shù)的區(qū)別在于友元可以直接訪問類的私有成員,而普通函數(shù)只能通過類的公有成員訪問其私有成員。6.1運算符重載基礎(chǔ)重載為成員與非成員函數(shù)的選擇“=,[],(),->”只能重載為類成員函數(shù)。一般而言,復(fù)合賦值運算符(如+=、-=、*=、/=等)通常應(yīng)該重載為類成員,但并不是必須這樣做(這一點與“=”不同);對于要改變對象狀態(tài)的運算符,或者與給定類型密切相關(guān)的運算符,如++(自增)、--(自減)、解引用運算符,也適宜重載為類成員函數(shù)。算術(shù)運算(+、*、/、-等)、相等與否的比較、關(guān)系運算、位運算等運算符具有對稱性,通常允許運算符左、右兩邊的對象進行交換或類型轉(zhuǎn)換,則適宜重載為非成員函數(shù)。6.1運算符重載基礎(chǔ)6.2重載二元運算符1、二元運算符的調(diào)用形式與解析aa@bb可解釋成aa.operator@(bb)

或解釋成operator@(aa,bb)如果兩者都有定義,就按照重載解析classX{public: voidoperator+(int); X(int);};voidoperator+(X,X);voidoperator+(X,double);voidf(Xa){a+2;//a.operator+(2)

2+a;//::operator+(X(2),a)

a+2.0;//::operator+(X,double);}6.2.1類與二元運算符重載1作為成員函數(shù)重載作為類的非靜態(tài)成員函數(shù)的二元運算符,只能夠有一個參數(shù),這個參數(shù)是運算符右邊的參數(shù),它的第一個參數(shù)是通過this指針傳遞的,其重載形式類似于下:classX{…… T1operator@(T2b){……};}其中,T1是運算符函數(shù)的返回類型,T2是參數(shù)的類型,原則上T1、T2可以是任何數(shù)據(jù)類型,但事實上它們常與X相同。2、作為友元或普通函數(shù)重載重載二元運算符為類的友元函數(shù)時需要兩個參數(shù),其形式如下:classX{……

friendT1operator@(T2a,T3b);}T1operator@(T2a,T3b){……}//友元:可直接訪問a,b私有成員T1operator#(T2a,T3b){……}//普通函數(shù):只能訪問a,b公有成員T1、T2、T3代表不同的數(shù)據(jù)類型,事實上它們常與類X相同。6.2.1類與二元運算符重載3、非靜態(tài)成員函數(shù)、普通函數(shù)、友元重載的區(qū)別以非靜態(tài)成員函數(shù)的方式重載二元運算符時,只能夠有一個參數(shù),它實際上是函數(shù)的第二個參數(shù)(即運算符右邊的操作數(shù)),其第一個參數(shù)(運算符左邊的操作數(shù))由C++通過this指針隱式傳遞,而作為普通函數(shù)和類的友元函數(shù)重載時需要兩個參數(shù);調(diào)用類的重載運算符時,作為類成員函數(shù)運算符的左參數(shù)必須是一個類對象,而作為友元或普通函數(shù)重載的運算符則無此限制。在某些情況下,只有非類成員函數(shù)重載才能解決某些特殊情況。6.2.1類與二元運算符重載【例6-1】設(shè)計復(fù)數(shù)類Complex,利用成員運算符函數(shù)重載實現(xiàn)復(fù)數(shù)的加、減運算,用友元運算符函數(shù)重載實現(xiàn)其乘、除等復(fù)數(shù)運算。#include<iostream>usingnamespacestd;classComplex{private:doubler,i;public:Complex(doubleR=0,doubleI=0):r(R),i(I){};Complexoperator+(Complexb); //L1復(fù)數(shù)加法Complexoperator-(Complexb); //L2復(fù)數(shù)減法friend Complexoperator*(Complexa,Complexb); //L3復(fù)數(shù)乘法friend Complexoperator/(Complexa,Complexb); //L4復(fù)數(shù)除法voiddisplay();};6.2.1類與二元運算符重載ComplexComplex::operator+(Complexb){returnComplex(r+b.r,i+b.i);}ComplexComplex::operator-(Complexb){returnComplex(r-b.r,i-b.i);}Complexoperator*(Complexa,Complexb){Complext;t.r=a.r*b.r-a.i*b.i;t.i=b.r*b.i+b.i*b.r;returnt;}Complexoperator/(Complexa,Complexb){

Complext;

doublex;

x=1/(b.r*b.r+b.i*b.i);t.r=x*(a.r*b.r+a.i*b.i);t.i=x*(a.i*b.r-a.r*b.i);

returnt;}voidComplex::display(){cout<<r;if(i>0)cout<<"+"; if(i!=0)cout<<i<<"i"<<endl;}voidmain(void){ Complexc1(1,2),c2(3,4),c3,c4,c5,c6; c3=c1+c2; c4=c1-c2; c5=c1*c2; c6=c1/c2; c1.display(); c2.display(); c3.display(); c4.display(); c5.display(); c6.display();}6.2.1類與二元運算符重載程序的運行結(jié)果如下:1+2i3+4i4+6i-2-2i-5+10i0.44+0.08i6.2.1類與二元運算符重載對于程序中的運算符調(diào)用c3=c1+c2;c4=c1-c2;C++會將它們轉(zhuǎn)換成下面形式的調(diào)用語句: c3=c1.operator+(c2); c4=c1.operator-(c2);從形式上看,這兩次函數(shù)調(diào)用只提供了一個參數(shù)c2,但實際上是兩個參數(shù),其左參數(shù)雖然沒有出現(xiàn)在參數(shù)表中,但編譯器會通過c1對象的this指針傳遞該參數(shù)。總括,在程序可用下面兩種方式調(diào)用以類成員函數(shù)方式重載的二元運算符:a@b;//隱式調(diào)用二元運算符@a.operator@(b)//顯式調(diào)用二元運算符@ComplexComplex::operator+(Complexb){returnComplex(r+b.r,i+b.i);}ComplexComplex::operator-(Complexb){returnComplex(r-b.r,i-b.i);}對于c5和c6的計算語句:c5=c1*c2;c6=c1/c2;因為“*”和“/”通過友元重載實現(xiàn)的,C++編譯器會將它們轉(zhuǎn)換成下面的函數(shù)調(diào)用形式:c5=operator*(c1,c2);c6=operator/(c1,c2);總括:以友元重載運算符函數(shù)在程序中可用下面兩種形式進行調(diào)用:a@b;//隱式調(diào)用二元運算符@operator@(a,b)//顯式調(diào)用二元運算符@6.2.1類與二元運算符重載Complexoperator*(Complexa,Complexb){Complext;t.r=a.r*b.r-a.i*b.i;t.i=b.r*b.i+b.i*b.r;returnt;}對于程序中的運算符調(diào)用:c3=c1+c2;c4=c1-c2;c5=c1*c2;c6=c1/c2;C++會將它們轉(zhuǎn)換成下面形式的調(diào)用語句:c3=c1.operator+(c2);c4=c1.operator–(c2);c5=operator*(c1,c2);c6=operator/(c1,c2);實際上,在程序中也可以直接寫出這樣的表達式,顯式調(diào)用重載的運算符函數(shù)6.2.1類與二元運算符重載6.2.2非類成員方式重載二元運算符的特殊用途1、解決運算符左、右操作數(shù)據(jù)的次序交換問題對于不要求返回左值且可以交換參數(shù)次序的運算符函數(shù)(如+、

、*、/等運算符),最好用非成員形式重載它(包括友元和普通函數(shù))。2、解決運算符左操作數(shù)據(jù)的類型轉(zhuǎn)換問題在調(diào)用重載的二元運算符函數(shù)時,如果第2個實參與形參的類型不匹配,C++將進行所有可能的隱式類型轉(zhuǎn)換。對于第一個參數(shù),就要分情況了:對于非類成員的重載運算符函數(shù),C++編譯器在參數(shù)不匹配的情況下將對第一個參數(shù)進行隱式類型轉(zhuǎn)換;對于以類成員重載的運算符函數(shù),不對第一個參數(shù)進行任何隱式類型轉(zhuǎn)換。【例6-2】設(shè)計復(fù)數(shù)類Complex,使它能夠?qū)崿F(xiàn)下列L1,L2式的加法運算。voidmain(){Complexc1,c2(1,2);c1=c2+2; //L1c1.display();c1=2+c2; //L2c1.display();}問題分析L1和L2兩條語句是數(shù)學(xué)中的常見運算,“+、-、×、/”等運算的兩個操作數(shù)可以交換次序。如果用類成員方式重載“+”,則只能完成L1語句的運算,L2語句則不能實現(xiàn)。解決這樣的問題,可以用友元重載“+”運算符。6.2.2非類成員方式重載二元運算符的特殊用途#include<iostream>usingnamespacestd;classComplex{private: doubler,i;public: Complex(doubleR=0,doubleI=0):r(R),i(I){}; friendComplexoperator+(Complexa,doubleb){ returnComplex(a.r+b,a.i); } friendComplexoperator+(doublea,Complexb){ returnComplex(a+b.r,b.i); } voiddisplay();};解決方案一:直接用兩個友元函數(shù)對不同類型參數(shù)進行運算的加法運算符voidComplex::display(){ cout<<r; if(i>0)cout<<"+"; if(i!=0)cout<<i<<"i"<<endl;}voidmain(void){ Complexc1(1,2),c2; c2=c1+5; c2.display();//輸出:6+2i c2=5+c1; c2.display();//輸出:6+2i}6.2.2非類成員方式重載二元運算符的特殊用途#include<iostream>usingnamespacestd;classComplex{private:doubler,i;public:Complex(doubleR=0,doubleI=0):r(R),i(I){};friendComplexoperator+(Complexa,Complexb){returnComplex(a.r+b.r,a.i+b.i);}voiddisplay();};voidComplex::display(){cout<<r;if(i>0)cout<<"+";if(i!=0)cout<<i<<"i"<<endl;}voidmain(void){Complexc1(1,2),c2;c2=c1+5;c2.display();//輸出:6+2ic2=5+c1;c2.display();//輸出:6+2i}解決方案二:通過1個友元函數(shù)重載對兩個Complex類型相加的加法運算符函數(shù)。這種方案要求:類應(yīng)具有能夠接受一個參數(shù)的構(gòu)造函數(shù),此構(gòu)造函數(shù)具有將此參數(shù)轉(zhuǎn)換為類類型的能力!6.3重載一元運算符

1、一元運算的概念一元運算符只需要一個運算參數(shù),如取地址運算符(&)、負(fù)數(shù)(

)、自增加(++)等。2、一元運算符常見調(diào)用形式@a或a@ //隱式調(diào)用形式a.operator@()//顯式調(diào)用一元運算符@其中的@代表一元運算符,a代表操作數(shù)。@a代表前綴一元運算,如“++a”;a@表示后綴運算,如“a++”。3、@a將被C++解釋為下面的形式之一a.operator@()//成員重載operator@(a)//友元重載6.3.1作為成員函數(shù)重載一元運算符作為類成員函數(shù)重載時不需要參數(shù),其形式如下:classX{…… Toperator@(){……};}T是運算符@的返回類型。從形式上看,作為類成員函數(shù)重載的一元運算符沒有參數(shù),但實際上它包含了一個隱含參數(shù),即調(diào)用對象的this指針。像++、--這樣能夠?qū)崿F(xiàn)連續(xù)自增、自減的運算符,其重載函數(shù)應(yīng)該返回對象的引用。否則,就不能實現(xiàn)對象的連續(xù)運算?!纠?-3】設(shè)計一個時間類Time,能夠完成秒鐘的自增運算。//Eg6-3.cpp#include<iostream>usingnamespacestd;classTime{private:inthour,minute,second;public:Time(inth,intm,ints);Time&operator++();voiddisplay();};Time::Time(inth,intm,ints){hour=h;minute=m;second=s;if(hour>=24)hour=0; //若初始小時超過24,重置為0if(minute>=60)minute=0; //若初始分鐘超過60,重置為0if(second>=60)second=0; //若初始秒鐘超過60,重置為0}6.3.1作為成員函數(shù)重載Time&Time::operator++(){++second;if(second>=60){second=0;++minute;if(minute>=60){minute=0;++hour;if(hour>=24)hour=0; }}return*this;}voidTime::display(){ cout<<hour<<":"<<minute<<":"<<second<<endl;}voidmain(){ Timet1(23,59,59); t1.display(); ++++t1;//隱式調(diào)用方式

t1.display(); t1.operator++();//顯式調(diào)用方式

t1.display();}本程序的運行結(jié)果如下:23:59:590:0:10:0:26.3.2作為友元函數(shù)重載用友元函數(shù)重載一元運算符時需要一個參數(shù)?!纠?-4】用友元重載Time類的自增運算符++。//Eg6-4.cppclassTime{ ……//省略的代碼與例6-3相同

friendTime&operator++(Time&t);};Time&operator++(Time&t){ ++t.second; if(t.second>=60){ t.second=0; ++t.minute; if(t.minute>=60){ t.minute=0; ++t.hour; if(t.hour>=24)t.hour=0; } } returnt;}voidmain(){ Timet1(23,59,59); t1.display();

++++t1; //隱式調(diào)用方式

t1.display();

operator++(t1); //顯式調(diào)用方式

t1.display();}本程序的運行結(jié)果:23:59:590:0:10:0:2此結(jié)果與例6-3完全相同6.3.2作為友元函數(shù)重載非類成員重載++、--等的注意事項在用友元和普通函數(shù)重載++、--這類一元運算符函數(shù)時,如果用值傳遞的方式設(shè)置函數(shù)的參數(shù),就可能會發(fā)生錯誤,不能把運算結(jié)果返回給調(diào)用對象。也就實現(xiàn)不了自增或自減運算6.3.2作為友元函數(shù)重載重載++運算符的錯誤例子將例6-4中的++運算符函數(shù)改為下面的重載形式:classTime{

……//Time類的其余代碼同例6-4friendTimeoperator++(Timet);};Timeoperator++(Timet){

……//省略的程序代碼同例6-4的operator++(Time&t)returnt;}……voidmain(){Timet1(23,59,59);t1.display();++++t1;t1.display();operator++(t1);t1.display();}本程序的運行結(jié)果如下23:59:5923:59:5923:59:59試分析此結(jié)果的由來!注意:形參和函數(shù)返回值都是值類型關(guān)于二元運算符重載的說法錯誤的是()重載為類成員函數(shù)時的參數(shù)數(shù)表只傳遞右操作數(shù)重載為非類成員函數(shù)時的參數(shù)表需要傳遞兩個參數(shù)重載為類成員函數(shù)時,左操作數(shù)據(jù)由this指針隱式傳遞可以重載為static成員函數(shù)ABCD提交單選題1分classComplex{doubler,I;public:Complex(doublerr=0,doublell=0):r(rr),l(ll){}Complex&operator+(Complexc){……}};Complexc1,c2(4,5),c3(1,2);針對上面的定義,下面的語句中,錯誤的是()C1=c2+c3;C1=c2+5.0;C1=5.0+c2;C1=Complex(5.0)+c2;ABCD提交單選題1分6.4特殊運算符重載6.4.1運算符++和--的重載1、特殊性:區(qū)分前綴、后綴++x; //前自增x++; //后自增--x; //前自減x--; //后自減2、將它們重載為類的成員函數(shù)時就會都是下面的形式:classX{…… Xoperator++(){……}; //前自增

Xoperator++(){……}; //后自增}6.4.1運算符++和--的重載3、重載為友元運算符,將都是下面的形式:classX{

friendXoperator++(X&o);//前自增的友元聲明

friendXoperator++(X&0);//后自增的友元聲明}4、問題?無法區(qū)分到底是前自增還是后自增運算!同樣的問題發(fā)生在自減運算符身上:--5、解決方案C++編譯器通過在運算符函數(shù)參數(shù)表中是否插入關(guān)鍵字int來區(qū)分這兩種方式。自減前綴

operator--();//成員函數(shù)重載

operator--(X&x);//自減后綴:加入一個無用的類型參數(shù),表示后綴

operator--(int); operator--(X&x,int);6.4.1運算符++和--的重載自增前綴

operator++();

//成員重載 operator++(X&x);//非成員重載自增后綴,增加一個無用參數(shù)

operator++(int);//成員重載 operator++(X&x,int);//非成員重載6.4.1運算符++和--的重載【例6-5】設(shè)計一個計數(shù)器counter,用數(shù)據(jù)成員n保存計算器的值,用類成員重載自增運算符實現(xiàn)計數(shù)器的自增,用友元重載實現(xiàn)計數(shù)器的自減。//Eg6-5.cpp#include<iostream>usingnamespacestd;classCounter{private: intn;public: Counter(inti=0){n=i;} Counter&operator++(); Counteroperator++(int); friendCounter&operator--(Counter&c); friendCounteroperator--(Counter&c,int); voiddisplay();};Counter&Counter::operator++(){ ++n; return*this;}CounterCounter::operator++(int){ Countert(*this); n++; returnt;}Counter&operator--(Counter&c){ --c.n; returnc;}Counteroperator--(Counter&c,int){ Countertemp(c); c.n--; returntemp;}voidCounter::display(){ cout<<"counternumber="<<n<<endl;}voidmain(){ Countera; ++a; //調(diào)用Counter::operator++() a.display(); a++; //調(diào)用Counter::operator++(int) a.display(); --a; //調(diào)用operator--(Counter&c) a.display(); a--; //調(diào)用operator--(Counter&c,int) a.display();}6.4.1運算符++和--的重載1、重載下標(biāo)運算符[](1)重載原因在C/C++中,數(shù)組不具有檢測下標(biāo)值范圍的功能,容易產(chǎn)生數(shù)組訪問下標(biāo)越界的錯誤。通過下標(biāo)運算符[]重載,可以在訪問數(shù)組元素時進行下標(biāo)值檢測,禁止越界訪問。(2)[]二元運算符的重載形式如下:classX{…… X&operator[](intn);};(3)重載[]需要注意的問題①[]是一個二元運算符,其第1個參數(shù)是通過對象的this指針傳遞的,第2個參數(shù)代表數(shù)組的下標(biāo)②由于[]既可以出現(xiàn)在賦值符“=”的左邊,也可以出現(xiàn)在賦值符“=”的右邊,所以重載運算符[]時常返回引用。③[]只能被重載為類的非靜態(tài)成員函數(shù),不能被重載為友元和普通函數(shù)。6.4.2下標(biāo)[]和賦值運算符=【例6-6】設(shè)計一個工資管理類,它能根據(jù)職工的姓名錄入和查詢職工的工資,每個職工的基本數(shù)據(jù)有職工姓名和工資。#include<iostream>#include<string>usingnamespacestd;structPerson{ //職工基本信息的結(jié)構(gòu)

doublesalary; char*name;};classSalaryManaege{ Person*employ; //存放職工信息的數(shù)組

intmax; //數(shù)組下標(biāo)上界

intn; //數(shù)組中的實際職工人數(shù)public: SalaryManaege(intMax=0){ max=Max; n=0; employ=newPerson[max]; }6.4.2下標(biāo)[]和賦值運算符=double&operator[](char*Name){ //重載[],返回引用

Person*p; for(p=employ;p<employ+n;p++) if(strcmp(p->name,Name)==0) returnp->salary; p=employ+n++; p->name=newchar[strlen(Name)+1]; strcpy(p->name,Name); p->salary=0; returnp->salary; }

voiddisplay(){ for(inti=0;i<n;i++) cout<<employ[i].name<<""<<employ[i].salary<<endl; }};6.4.2下標(biāo)[]和賦值運算符=voidmain(){ SalaryManaeges(3); s["杜一為"]=2188.88; s["李海山"]=1230.07; s["張軍民"]=3200.97; cout<<"杜一為\t"<<s["杜一為"]<<endl; cout<<"李海山\t"<<s["李海山"]<<endl; cout<<"張軍民\t"<<s["張軍民"]<<endl;

cout<<"-------下為display的輸出--------\n\n"; s.display();}6.4.2下標(biāo)[]和賦值運算符=2.重載賦值運算符=(1)賦值運算符“=”的重載特殊性賦值運算進行時將調(diào)用此運算符只能用成員函數(shù)重載“=”應(yīng)用場合較多。在設(shè)計類時若沒有為它提供賦值運算符成員函數(shù),編譯器會自動為它合成一個默認(rèn)的賦值運算符函數(shù)。(2)什么時侯需要重載“=”如果該類對象沒有分配動態(tài)存儲空間,默認(rèn)賦值運算符函數(shù)能夠正確完成對象的賦值拷貝。如果對象構(gòu)造時分配了動態(tài)存儲空間,默認(rèn)賦值運算符函數(shù)多數(shù)時候都不能正確地進行對象的賦值拷貝,需要為類重載賦值運算符函數(shù)。此外,有時還需要通過賦值運算符實現(xiàn)特殊的對象賦值拷貝操作,也需要重載賦值運符函數(shù)。關(guān)于重載賦值運算符函數(shù)的詳細(xì)內(nèi)容,請參3.8.1節(jié)6.4.2下標(biāo)[]和賦值運算符=1、關(guān)于類型轉(zhuǎn)換運算C++是強類型語言,類型轉(zhuǎn)換經(jīng)常發(fā)生兩種類型轉(zhuǎn)換隱式類型轉(zhuǎn)換implicitconversion顯式類型轉(zhuǎn)換explicitconversion隱式類型轉(zhuǎn)換發(fā)生的時機賦值函數(shù)調(diào)用函數(shù)返回值6.4.3類型轉(zhuǎn)換運算符下面的說法正確的是()A&Operatr++(A&a)是后綴自增重載[]可以重載為普通成員函數(shù)[]只能重載為類成員函數(shù)只能將+、-運算符重載為類的友元函數(shù)ABCD提交單選題1分隱式類型轉(zhuǎn)換示例classX{ public:

X(int){cout<<"X"<<endl;}};Xf(X){return1;}//將int轉(zhuǎn)換成X類型voidmain(void){ inti='a'; Xobj=f(i); f('b');}顯示類型轉(zhuǎn)換longi=(long)1234;longi=long(1234);6.4.3類型轉(zhuǎn)換運算符2、用構(gòu)造函數(shù)實現(xiàn)類的類型轉(zhuǎn)換若將類Y轉(zhuǎn)換成類X類型,用如下形式的構(gòu)造函數(shù)classX{ public:X(Yy){……};};…Yy;Xx1=y;Xx2(y);x1=y;……6.4.3類型轉(zhuǎn)換運算符【例6-7】有日期類Date,設(shè)計其構(gòu)造函數(shù),能夠?qū)⒄蛿?shù)據(jù)轉(zhuǎn)換成一個Date類的對象。#include<iostream>usingnamespacestd;classDate{private: intyear,month,day;public: Date(intyy=1900,intmm=1,intdd=1){year=yy;month=mm;day=dd;} voidShow(){cout<<year<<"-"<<month<<"-"<<day<<endl;}};voidmain(){ Dated(2000,10,11); d.Show();

d=2006; d.Show();}將調(diào)用構(gòu)造函數(shù)將2006轉(zhuǎn)換成Date3.類型轉(zhuǎn)換運算符用于將類X轉(zhuǎn)換為類Y類型。語法classX{ public:operatorY() { …… returnY類型的數(shù)據(jù);};};類型轉(zhuǎn)換函數(shù)沒有參數(shù),沒有返回類型。類型轉(zhuǎn)換函數(shù)必須返回將要轉(zhuǎn)換成的type類型數(shù)據(jù)。一旦定義類型轉(zhuǎn)換運算符,就可以顯示或隱式地進行類型轉(zhuǎn)換,如同系統(tǒng)預(yù)定義的類型轉(zhuǎn)換一樣。6.4.3類型轉(zhuǎn)換運算符【例6-8】有一個類Circle,設(shè)計該類的類型轉(zhuǎn)換函數(shù),當(dāng)將Circle對象轉(zhuǎn)換成int型時,返回圓的半徑;當(dāng)將它轉(zhuǎn)換成double型時,就返回圓的周長;當(dāng)將它轉(zhuǎn)換成float型時,就返回圓的面積。//Eg6-8.cpp#include<iostream>usingnamespacestd;classCircle{private: doublex,y,r;public: Circle(doublex1,doubley1,doubler1){x=x1;y=y1;r=r1;} operatorint(){returnint(r);} operatordouble(){return2*3.14*r;} operatorfloat(){return(float)3.14*r*r;}};voidmain(){ Circlec(2.3,3.4,2.5);

intr=c;//調(diào)用operatorint(),將Circle類型轉(zhuǎn)換成int

doublelength=c;//調(diào)用operatordouble(),轉(zhuǎn)換成double

floatarea=c;//調(diào)用operatorfloat(),將Circle類型轉(zhuǎn)換成float

doublelen=(double)c;//將Cirlce類型對象強制轉(zhuǎn)換成double cout<<r<<endl; cout<<length<<endl; cout<<len<<endl; cout<<area<<endl;}6.4.3類型轉(zhuǎn)換運算符4.類型轉(zhuǎn)換的二義性問題無論是定義把其它類型轉(zhuǎn)換成類類型的構(gòu)造函數(shù),還是定義把類類型轉(zhuǎn)換成其它類型的類型轉(zhuǎn)換運算符函數(shù),都要注意避免轉(zhuǎn)換函數(shù)的二義性問題。最常見的情況是定義多個參數(shù)都是數(shù)值類型的構(gòu)造函數(shù),或者定義了多個目標(biāo)類型都是數(shù)值類型的類型轉(zhuǎn)換函數(shù)?!纠?-9】類B同時設(shè)置了int和double類型參數(shù)的構(gòu)造函數(shù),以及將類B轉(zhuǎn)換成int和float的類型轉(zhuǎn)換函數(shù),容易引發(fā)二義性問題。6.4.3類型轉(zhuǎn)換運算符#include<iostream>usingnamespacestd;classB{ doublex;public:

B(floata=0):x(a){}

B(doubleb=0.0):x(b){} operatorint(){returnx;} operatorfloat(){returnx;}};voidf(longl){cout<<l<<endl;}voidmain(){

Bb(4);//L1,無法確定調(diào)用B::B(float)還是B::B(double)

f(b);//L2,無法確定調(diào)用operatorint()還是operatorfloat()}6.4.3類型轉(zhuǎn)換運算符6.4.4仿函數(shù)1、運算符()是函數(shù)調(diào)用運算符,稱為仿函數(shù),也能被重載。且只能被重載為類的成員函數(shù)。2、運算符()的重載形式如下:classX{…… X&operator()(參數(shù)表);};其中的參數(shù)表可以包括任意多個參數(shù)。3、運算符()的調(diào)用形式如下:XObj; //對象定義Obj()(參數(shù)表); //調(diào)用形式1Obj(參數(shù)表); //調(diào)用形式2【例6-10】設(shè)計點類Point,具有表示坐標(biāo)位置的數(shù)據(jù)成員x,y,重載函數(shù)調(diào)用運算符,其功能是可以用指定的參數(shù)移動坐標(biāo)x、y,或者輸出點的坐標(biāo)值。#include<iostream>usingnamespacestd;classPoint{public: Point(inta=0,intb=0):x(a),y(b){} Point&operator()(intdx,intdy){ //函數(shù)調(diào)用運算符 x+=dx;y+=dy; return*this; } 6.4.4仿函數(shù)Pointoperator()(intdxy){//函數(shù)調(diào)用運算符 x+=dxy;y+=dxy; return*this; }

voidoperator()(){//函數(shù)調(diào)用運算符 cout<<"["<<x<<","<<y<<"]"<<endl; }private: intx,y;};intmain(){ Pointpt,pt2(2,2);//L1,調(diào)用Point::Point()和Point::Point(int,int)

pt=pt2(3,6);//L2,調(diào)用Point::operator(int,int)

pt();//L3,調(diào)用Point::operator(),輸出:[5,8]

pt2(6);//L4,調(diào)用Point::operator(int)

pt2();//L5,調(diào)用Point::operator(),輸出:[11,14]}6.5輸入/輸出運算符重載6.6.1重載輸出運算符<<輸出運算符<<也稱為插入運算符,通過輸出運算符<<的重載可以實現(xiàn)用戶自定義數(shù)據(jù)類型的輸出。<<的重載語法ostream&operator<<(ostream&os,classTypeobject){ …… os<<… //輸出對象的實際成員數(shù)據(jù)

returnos; //返回ostream對象}輸入運算符>>也稱為提取運算符,用于輸入數(shù)據(jù)。通過輸入運算符>>的重載,就能夠用它輸

入用戶自定義的數(shù)據(jù)類型>>的重載語法istream&operator>>(istream&is,class_name&object){ …… is>>… //輸入對象object的實際成員數(shù)據(jù)

returnis; //返回istream對象}6.5.2重載輸入運算符>>6.5.3>>和<<重載的應(yīng)用【例6-11】有一銷售人員類Sales,其數(shù)據(jù)成員有姓名name,身份證號id,年齡age。重載輸入輸出運算符實現(xiàn)對Sales類數(shù)據(jù)成員的輸入和輸出。#include<iostream>#include<string>usingnamespacestd;classSales{private: stringname; stringid; intage;public: Sales(stringName,stringID,intAge);

friend ostream&operator<<(ostream&os,Sales&s);

friend istream&operator>>(istream&is,Sales&s);

};Sales::Sales(stringName,stringID,intAge){ name=Name; id=ID; age=Age;}ostream&operator<<(ostream&os,Sales&s){ os<<<<"\t"; //輸出姓名 os<<s.id<<"\t"; //輸出身份證號 os<<s.age<<endl; //輸出年齡 returnos;}istream&operator>>(istream&is,Sales&s){ cout<<"輸入雇員的姓名,身份證號,年齡"<<endl; is>>>>s.id>>s.age;//數(shù)據(jù)成員數(shù)據(jù)輸入 returnis;}6.5.3>>和<<重載的應(yīng)用voidmain(){ Saless1("杜康","214198012111711",40); cout<<s1; cout<<endl; cin>>s1; cout<<s1;}6.5.3>>和<<重載的應(yīng)用程序運行結(jié)果如下:杜康 214198012111711 40輸入雇員的姓名,身份證號,年齡Tom10023Tom 100 236.6編程實作:運算符重載編程應(yīng)用1.編程實例一【例6-12】

設(shè)計一個字符串類String,通過運算符重載實現(xiàn)字符串的輸入、輸出以及+=、==、!=、<、>、>=、[]等運算。問題分析:標(biāo)準(zhǔn)C++提供了一個String類。String類重載了+、+=、==、>、>=、<、<=等運算符函數(shù),這些重載運算符函數(shù)讓字符串?dāng)?shù)據(jù)類型的操作變得非常簡單,使字符串的賦值、連接與大小比較等操作與C++內(nèi)置的int和float等類型的數(shù)據(jù)一樣簡便。要使用標(biāo)準(zhǔn)C++的string類,需在程序中引用頭文件#include<string>。在此可以通過運算符重載實現(xiàn)字符串的+=、==、!=、<、>、>=、[]#include<iostream>usingnamespacestd;classString{private:intlength; //字符串長度char*sPtr; //存放字符串的指針voidsetString(constchar*s2); friendostream&operator<<(ostream&os,constString&s);friendistream&operator>>(istream&is,String&s);public:String(constchar*="");~String(); constString&operator=(constString&R); constString&operator+=(constString&R);booloperator==(constString&R); booloperator!=(constString&R); booloperator!(); booloperator<(constString&R)const; booloperator>(constString&R);booloperator>=(constString&R);char&operator[](int);};constString&String::operator+=(constString&R){char*temp=sPtr;length+=R.length;sPtr=newchar[length+1];strcpy(sPtr,temp);strcat(sPtr,R.sPtr);delete[]temp;return*this;}boolString::operator==(constString&R){returnstrcmp(sPtr,R.sPtr)==0;}boolString::operator!=(constString&R){return!(*this==R);}boolString::operator!(){returnlength==0;}boolString::operator<(constString&R)const{returnstrcmp(sPtr,R.sPtr)<0;}boolString::operator>(constString&R){returnR<*this;}boolString::operator>=(constString&R){return!(*this<R);}char&String::operator[](intsubscript){returnsPtr[subscript];}ostream&operator<<(ostream&os,constString&s){os<<s.sPtr;returnos;}istream&operator>>(istream&is,String&s){chartemp[100];s=temp;returnis;}intmain(){Strings1("happy"),s2("newyear"),s3;cout<<"s1is"<<s1<<"\ns2is"<<s2<<"\ns3is"<<s3<<"\n比較s2和s1:"<<"\ns2==s1結(jié)果是"<<(s2==s1?"true":"false")<<"\ns2!=s1結(jié)果是"<<(s2!=s1?"true":"false")<<"\ns2>s1結(jié)果是"<<(s2>s1?"true":"false")<<"\ns2<s1結(jié)果是"<<(s2<s1?"true":"false")<<"\ns2>=s1結(jié)果是"<<(s2>=s1?"true":"false");cout<<"\n\n測試s3是否為空:"; if(!s3){cout<<"s3是空串"<<endl; //L3cout<<"把s1賦給s3的結(jié)果是:"; s3=s1; cout<<"s3="<<s3<<"\n";//L5}cout<<"s1+=s2的結(jié)果是:s1="; //L6s1+=s2;cout<<s1; //L7

cout<<"\ns1+=toyou的結(jié)果是:";//L8s1+="toyou";cout<<"s1="<<s1<<endl; //L9s1[0]='H';s1[6]='N';s1[10]='Y';cout<<"s1="<<s1<<"\n";//L10return0;}程序運行結(jié)果s1ishappy //L1語句輸出下面連續(xù)的9行s2isnewyears3is比較s2和s1:s2==s1結(jié)果是falses2!=s1結(jié)果是trues2>s1結(jié)果是falses2<s1結(jié)果是trues2>=s1結(jié)果是false測試s3是否為空:s3是空串 //L2和L3語句輸出把s1賦給s3的結(jié)果是:s3=happy //L4和L5語句輸出s1+=s2的結(jié)果是:s1=happynewyear //L6和L7語句輸出s1+=toyou的結(jié)果是:s1=happynewyeartoyou //L8和L9語句輸出s1=HappyNewYeartoyou //L10語句輸出6.6編程實作:運算符重載編程應(yīng)用2.編程實例二【例6-13】改寫5.5節(jié)的課程結(jié)構(gòu)類,為comFinal、Account、Chemistry類重載輸出運算符函數(shù)operator<<,使程序能夠直接利用cout輸出各個類的對象。(1)重載comFinal類的輸出運算符operator<<啟動VC++,打開目錄C:\course中的com_main.sln工程文件;打開comFinal.h頭文件,并在comFinal類的聲明中添加operator<<運算符函數(shù)的重載聲明,如下所示://comFinal.hclasscomFinal{friend ostream&operator<<(ostream&os,comFinal&s);

…… //其余代碼不作任何修改;}

打開comFinal.cpp源文件,并在其中添加operator<<的程序代碼。代碼如下:

//comFinal.cpp……ostream&operator<<(ostream&out,comFinal&o){ cout<<"姓名\t"<<"漢語\t"<<"數(shù)學(xué)\t"<<"英語\t" <<"總分\t"<<"平均分"<<endl; out<<<<"\t"<<o.chinese<<"\t"<<o.math<<"\t"<<o.english<<"\t" <<o.getTotal()<<"\t"<<o.getAverage()<<endl<<endl; returnout;}6.6編程實例(2)重載Account類的輸出運算符operator<<在Account頭文件的類中添加如下函數(shù)聲明:

//Account.hclassAccount{friend ostream&operator<<(ostream&os,Account&s);

…… //其余代碼不作任何修改}添加在Account.cpp中的實現(xiàn)代碼如下:

//Account.cppostream&operator<<(ostream&out,Account&o){ cout<<"姓名\t"<<"漢語\t"<<"數(shù)學(xué)\t"<<"英語\t" <<"會計學(xué)\t"<<"經(jīng)濟學(xué)\t"<<"總分\t"<<"平均分"<<endl; out<<<<"\t"<<o.chinese<<"\t"<<o.math<<"\t"<<o.english<<"\t" <<o.account<<"\t"<<o.econ<<"\t"<<o.getTotal()+o.account+o.econ<<"\t"<<(o.getTotal()+o.account+o.econ)/5<<endl<<endl; returnout;}(3)重載Chemistry類的輸出運算符:operator<<在Chemistry類的頭文件和源代碼中分別添加如下代碼:

//Chemistry.hclassChemistry{ friendostream&operator<<(ostream&os,Chemistry&s);……

其余代碼不作任何修改;}添加在Chemistry.cpp文件中的函數(shù)代碼如下:

//Chemistry.cppostream&operator<<(ostream&out,Chemistry&o){ cout<<"姓名\t"<<"漢語\t"<<"數(shù)學(xué)\t"<<"英語\t"<<"化學(xué)\t" <<"化學(xué)分析\t"<<"總分\t"<<"平均分"<<endl; out<<<<"\t"<<o.chinese<<"\t"<<o.math<<"\t" <<o.english<<"\t"<<o.chemistr<<"\t"<<o.analy<<"\t\t" <<o.getTotal()+o.chemistr+o.analy<<"\t" <<(o.getTotal()+o.chemistr+o.analy)/5<<endl<<endl; returnout;}(4)驗證重載結(jié)果改寫應(yīng)用程序的主函數(shù)main(),如下所示:

//com_main.cpp#include"Chemistry.h"#include"Account.h"#include<iostream.h>voidmain(){comFinalcom("劉科學(xué)",78,76,89);Accounta1("張三星",98,78,97,67,87);Chemistryc1("光紅順",89,76,34,56,78);

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論