![第10章-C++程序設(shè)計(譚浩強)電子課件_第1頁](http://file4.renrendoc.com/view10/M03/32/08/wKhkGWWV6v2AMsFpAAItCBVGSbw372.jpg)
![第10章-C++程序設(shè)計(譚浩強)電子課件_第2頁](http://file4.renrendoc.com/view10/M03/32/08/wKhkGWWV6v2AMsFpAAItCBVGSbw3722.jpg)
![第10章-C++程序設(shè)計(譚浩強)電子課件_第3頁](http://file4.renrendoc.com/view10/M03/32/08/wKhkGWWV6v2AMsFpAAItCBVGSbw3723.jpg)
![第10章-C++程序設(shè)計(譚浩強)電子課件_第4頁](http://file4.renrendoc.com/view10/M03/32/08/wKhkGWWV6v2AMsFpAAItCBVGSbw3724.jpg)
![第10章-C++程序設(shè)計(譚浩強)電子課件_第5頁](http://file4.renrendoc.com/view10/M03/32/08/wKhkGWWV6v2AMsFpAAItCBVGSbw3725.jpg)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第10章運算符重載10.1什么是運算符重載10.2運算符重載的方法10.3重載運算符的規(guī)那么10.4運算符重載函數(shù)作為類成員函數(shù)和友元函數(shù)10.5重載雙目運算符10.6重載單目運算符10.7重載流插入運算符和流提取運算符10.8不同類型數(shù)據(jù)間的轉(zhuǎn)換所謂重載,就是重新賦予新的含義。函數(shù)重載就是對一個已有的函數(shù)賦予新的含義,使之實現(xiàn)新功能。運算符也可以重載。實際上,我們已經(jīng)在不知不覺之中使用了運算符重載?,F(xiàn)在要討論的問題是:用戶能否根據(jù)自己的需要對C++已提供的運算符進行重載,賦予它們新的含義,使之一名多用。譬如,能否用“+〞號進行兩個復數(shù)的相加。在C++中不能在程序中直接用運算符“+〞對復數(shù)進行相加運算。用戶必須自己設(shè)法實現(xiàn)復數(shù)相加。例如用戶可以通過定義一個專門的函數(shù)來實現(xiàn)復數(shù)相加。見例10.1。10.1什么是運算符重載例10.1通過函數(shù)來實現(xiàn)復數(shù)相加。#include<iostream>usingnamespacestd;classComplex//定義Complex類{public:Complex(){real=0;imag=0;}//定義構(gòu)造函數(shù)Complex(doubler,doublei){real=r;imag=i;}//構(gòu)造函數(shù)重載Complexcomplex_add(Complex&c2);//聲明復數(shù)相加函數(shù)voiddisplay();//聲明輸出函數(shù)
private:doublereal;//實部doubleimag;//虛部};ComplexComplex∷complex_add(Complex&c2){Complexc;c.real=real+c2.real;c.imag=imag+c2.imag;returnc;}voidComplex∷display()//定義輸出函數(shù){cout<<″(″<<real<<″,″<<imag<<″i)″<<endl;}intmain(){Complexc1(3,4),c2(5,-10),c3;//定義3個復數(shù)對象c3=c1plex_add(c2);//調(diào)用復數(shù)相加函數(shù)cout<<″c1=″;c1.display();//輸出c1的值cout<<″c2=″;c2.display();//輸出c2的值cout<<″c1+c2=″;c3.display();//輸出c3的值return0;}運行結(jié)果如下:c1=(3+4i)c2=(5-10i)c1+c2=(8,-6i)結(jié)果無疑是正確的,但調(diào)用方式不直觀、太煩瑣,使人感到很不方便。能否也和整數(shù)的加法運算一樣,直接用加號“+〞來實現(xiàn)復數(shù)運算呢?如c3=c1+c2;編譯系統(tǒng)就會自動完成c1和c2兩個復數(shù)相加的運算。如果能做到,就為對象的運算提供了很大的方便。這就需要對運算符“+〞進行重載。運算符重載的方法是定義一個重載運算符的函數(shù),在需要執(zhí)行被重載的運算符時,系統(tǒng)就自動調(diào)用該函數(shù),以實現(xiàn)相應的運算。也就是說,運算符重載是通過定義函數(shù)實現(xiàn)的。運算符重載實質(zhì)上是函數(shù)的重載。重載運算符的函數(shù)一般格式如下:函數(shù)類型operator運算符名稱(形參表列){對運算符的重載處理}例如,想將“+〞用于Complex類(復數(shù))的加法運算,函數(shù)的原型可以是這樣的:Complexoperator+(Complex&c1,Complex&c2);10.2運算符重載的方法在定義了重載運算符的函數(shù)后,可以說:函數(shù)operator+重載了運算符+。為了說明在運算符重載后,執(zhí)行表達式就是調(diào)用函數(shù)的過程,可以把兩個整數(shù)相加也想像為調(diào)用下面的函數(shù):intoperator+(inta,intb){return(a+b);}如果有表達式5+8,就調(diào)用此函數(shù),將5和8作為調(diào)用函數(shù)時的實參,函數(shù)的返回值為13。這就是用函數(shù)的方法理解運算符??梢栽诶?0.1程序的根底上重載運算符“+〞,使之用于復數(shù)相加。例10.2改寫例10.1,重載運算符“+〞,使之能用于兩個復數(shù)相加。#include<iostream>usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}Complexoperator+(Complex&c2);//聲明重載運算符的函數(shù)voiddisplay();private:doublereal;doubleimag;};ComplexComplex∷operator+(Complex&c2)//定義重載運算符的函數(shù){Complexc;c.real=real+c2.real;c.imag=imag+c2.imag;returnc;}voidComplex∷display(){cout<<″(″<<real<<″,″<<imag<<″i)″<<endl;}intmain(){Complexc1(3,4),c2(5,-10),c3;c3=c1+c2;//運算符+用于復數(shù)運算cout<<″c1=″;c1.display();cout<<″c2=″;c2.display();cout<<″c1+c2=″;c3.display();return0;}運行結(jié)果與例10.1相同:c1=(3+4i)c2=(5-10i)c1+c2=(8,-6i)請比較例10.1和例10.2,只有兩處不同:(1)在例10.2中以operator+函數(shù)取代了例10.1中的complex_add函數(shù),而且只是函數(shù)名不同,函數(shù)體和函數(shù)返回值的類型都是相同的。(2)在main函數(shù)中,以“c3=c1+c2;〞取代了例10.1中的“c3=c1plex_add(c2);〞。在將運算符+重載為類的成員函數(shù)后,C++編譯系統(tǒng)將程序中的表達式c1+c2解釋為c1.operator+(c2)//其中c1和c2是Complex類的對象即以c2為實參調(diào)用c1的運算符重載函數(shù)operator+(Complex&c2),進行求值,得到兩個復數(shù)之和。雖然重載運算符所實現(xiàn)的功能完全可以用函數(shù)實現(xiàn),但是使用運算符重載能使用戶程序易于編寫、閱讀和維護。在實際工作中,類的聲明和類的使用往往是別離的。假設(shè)在聲明Complex類時,對運算符+,-,*,/都進行了重載,那么使用這個類的用戶在編程時可以完全不考慮函數(shù)是怎么實現(xiàn)的,放心大膽地直接使用+,-,*,/進行復數(shù)的運算即可,十分方便。對上面的運算符重載函數(shù)operator+還可以改寫得更簡練一些:ComplexComplex∷operator+(Complex&c2){returnComplex(real+c2.real,imag+c2.imag);}需要說明的是:運算符被重載后,其原有的功能仍然保存,沒有喪失或改變。通過運算符重載,擴大了C++已有運算符的作用范圍,使之能用于類對象。運算符重載對C++有重要的意義,把運算符重載和類結(jié)合起來,可以在C++程序中定義出很有實用意義而使用方便的新的數(shù)據(jù)類型。運算符重載使C++具有更強大的功能、更好的可擴充性和適應性,這是C++最吸引人的特點之一。(1)C++不允許用戶自己定義新的運算符,只能對已有的C++運算符進行重載。〔2〕C++允許重載的運算符C++中絕大局部的運算符允許重載。具體規(guī)定見書中表10.1。不能重載的運算符只有5個:.(成員訪問運算符).*(成員指針訪問運算符)∷(域運算符)sizeof(長度運算符)?:(條件運算符)10.3重載運算符的規(guī)那么前兩個運算符不能重載是為了保證訪問成員的功能不能被改變,域運算符和sizeof運算符的運算對象是類型而不是變量或一般表達式,不具重載的特征。(3)重載不能改變運算符運算對象(即操作數(shù))的個數(shù)。(4)重載不能改變運算符的優(yōu)先級別。(5)重載不能改變運算符的結(jié)合性。(6)重載運算符的函數(shù)不能有默認的參數(shù),否那么就改變了運算符參數(shù)的個數(shù),與前面第(3)點矛盾。(7)重載的運算符必須和用戶定義的自定義類型的對象一起使用,其參數(shù)至少應有一個是類對象(或類對象的引用)。也就是說,參數(shù)不能全部是C++的標準類型,以防止用戶修改用于標準類型數(shù)據(jù)的運算符的性質(zhì)。(8)用于類對象的運算符一般必須重載,但有兩個例外,運算符“=〞和“&〞不必用戶重載。①賦值運算符(=)可以用于每一個類對象,可以利用它在同類對象之間相互賦值。②地址運算符&也不必重載,它能返回類對象在內(nèi)存中的起始地址。(9)應當使重載運算符的功能類似于該運算符作用于標準類型數(shù)據(jù)時所實現(xiàn)的功能。(10)運算符重載函數(shù)可以是類的成員函數(shù)(如例10.2),也可以是類的友元函數(shù),還可以是既非類的成員函數(shù)也不是友元函數(shù)的普通函數(shù)。在本章例10.2程序中對運算符“+〞進行了重載,使之能用于兩個復數(shù)的相加。在該例中運算符重載函數(shù)operator+作為Complex類中的成員函數(shù)?!?〞是雙目運算符,為什么在例10.2程序中的重載函數(shù)中只有一個參數(shù)呢?實際上,運算符重載函數(shù)有兩個參數(shù),由于重載函數(shù)是Complex類中的成員函數(shù),有一個參數(shù)是隱含的,運算符函數(shù)是用this指針隱式地訪問類對象的成員。10.4運算符重載函數(shù)作為類成員函數(shù)和友元函數(shù)可以看到,重載函數(shù)operator+訪問了兩個對象中的成員,一個是this指針指向的對象中的成員,一個是形參對象中的成員。如this->real+c2.real,this->real就是c1.real。在10.2節(jié)中已說明,在將運算符函數(shù)重載為成員函數(shù)后,如果出現(xiàn)含該運算符的表達式,如c1+c2,編譯系統(tǒng)把它解釋為c1.operator+(c2)即通過對象c1調(diào)用運算符重載函數(shù),并以表達式中第二個參數(shù)(運算符右側(cè)的類對象c2)作為函數(shù)實參。運算符重載函數(shù)的返回值是Complex類型,返回值是復數(shù)c1和c2之和(Complex(c1.real+c2.real,c1.imag+c2.imag))。運算符重載函數(shù)除了可以作為類的成員函數(shù)外,還可以是非成員函數(shù)。可以將例10.2改寫為例10.3。例10.3將運算符“+〞重載為適用于復數(shù)加法,重載函數(shù)不作為成員函數(shù),而放在類外,作為Complex類的友元函數(shù)。#include<iostream>usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}friendComplexoperator+(Complex&c1,Complex&c2);//重載函數(shù)作為友元函數(shù)voiddisplay();private:doublereal;doubleimag;};Complexoperator+(Complex&c1,Complex&c2)//定義作為友元函數(shù)的重載函數(shù){returnComplex(c1.real+c2.real,c1.imag+c2.imag);}voidComplex∷display(){cout<<″(″<<real<<″,″<<imag<<″i)″<<endl;}intmain(){Complexc1(3,4),c2(5,-10),c3;c3=c1+c2;cout<<″c1=″;c1.display();cout<<″c2=″;c2.display();cout<<″c1+c2=″;c3.display();}與例10.2相比較,只作了一處改動,將運算符函數(shù)不作為成員函數(shù),而把它放在類外,在Complex類中聲明它為友元函數(shù)。同時將運算符函數(shù)改為有兩個參數(shù)。在將運算符“+〞重載為非成員函數(shù)后,C++編譯系統(tǒng)將程序中的表達式c1+c2解釋為operator+(c1,c2)即執(zhí)行c1+c2相當于調(diào)用以下函數(shù):Complexoperator+(Complex&c1,Complex&c2){returnComplex(c1.real+c2.real,c1.imag+c2.imag);}求出兩個復數(shù)之和。運行結(jié)果同例10.2。為什么把運算符函數(shù)作為友元函數(shù)呢?因為運算符函數(shù)要訪問Complex類對象中的成員。如果運算符函數(shù)不是Complex類的友元函數(shù),而是一個普通的函數(shù),它是沒有權(quán)利訪問Complex類的私有成員的。在10.2節(jié)中曾提到過:運算符重載函數(shù)可以是類的成員函數(shù),也可以是類的友元函數(shù),還可以是既非類的成員函數(shù)也不是友元函數(shù)的普通函數(shù)?,F(xiàn)在分別討論這3種情況。首先,只有在極少的情況下才使用既不是類的成員函數(shù)也不是友元函數(shù)的普通函數(shù),原因是上面提到的,普通函數(shù)不能直接訪問類的私有成員。在剩下的兩種方式中,什么時候應該用成員函數(shù)方式,什么時候應該用友元函數(shù)方式?二者有何區(qū)別呢?如果將運算符重載函數(shù)作為成員函數(shù),它可以通過this指針自由地訪問本類的數(shù)據(jù)成員,因此可以少寫一個函數(shù)的參數(shù)。但必須要求運算表達式第一個參數(shù)(即運算符左側(cè)的操作數(shù))是一個類對象,而且與運算符函數(shù)的類型相同。因為必須通過類的對象去調(diào)用該類的成員函數(shù),而且只有運算符重載函數(shù)返回值與該對象同類型,運算結(jié)果才有意義。在例10.2中,表達式c1+c2中第一個參數(shù)c1是Complex類對象,運算符函數(shù)返回值的類型也是Complex,這是正確的。如果c1不是Complex類,它就無法通過隱式this指針訪問Complex類的成員了。如果函數(shù)返回值不是Complex類復數(shù),顯然這種運算是沒有實際意義的。如想將一個復數(shù)和一個整數(shù)相加,如c1+i,可以將運算符重載函數(shù)作為成員函數(shù),如下面的形式:ComplexComplex∷operator+(int&i)//運算符重載函數(shù)作為Complex類的成員函數(shù){returnComplex(real+i,imag);}注意在表達式中重載的運算符“+〞左側(cè)應為Complex類的對象,如c3=c2+i;不能寫成c3=i+c2;//運算符“+〞的左側(cè)不是類對象,編譯出錯如果出于某種考慮,要求在使用重載運算符時運算符左側(cè)的操作數(shù)是整型量〔如表達式i+c2,運算符左側(cè)的操作數(shù)i是整數(shù)〕,這時是無法利用前面定義的重載運算符的,因為無法調(diào)用i.operator+函數(shù)??上攵?,如果運算符左側(cè)的操作數(shù)屬于C++標準類型(如int)或是一個其他類的對象,那么運算符重載函數(shù)不能作為成員函數(shù),只能作為非成員函數(shù)。如果函數(shù)需要訪問類的私有成員,那么必須聲明為友元函數(shù)??梢栽贑omplex類中聲明:friendComplexoperator+(int&i,Complex&c);//第一個參數(shù)可以不是類對象在類外定義友元函數(shù):Complexoperator+(int&i,Complex&c)//運算符重載函數(shù)不是成員函數(shù){returnComplex(i+c.real,c.imag);}將雙目運算符重載為友元函數(shù)時,在函數(shù)的形參表列中必須有兩個參數(shù),不能省略,形參的順序任意,不要求第一個參數(shù)必須為類對象。但在使用運算符的表達式中,要求運算符左側(cè)的操作數(shù)與函數(shù)第一個參數(shù)對應,運算符右側(cè)的操作數(shù)與函數(shù)的第二個參數(shù)對應。如c3=i+c2;//正確,類型匹配c3=c2+i;//錯誤,類型不匹配請注意,數(shù)學上的交換律在此不適用。如果希望適用交換律,那么應再重載一次運算符“+〞。如Complexoperator+(Complex&c,int&i)//此時第一個參數(shù)為類對象{returnComplex(i+c.real,c.imag);}這樣,使用表達式i+c2和c2+i都合法,編譯系統(tǒng)會根據(jù)表達式的形式選擇調(diào)用與之匹配的運算符重載函數(shù)。可以將以上兩個運算符重載函數(shù)都作為友元函數(shù),也可以將一個運算符重載函數(shù)(運算符左側(cè)為對象名的)作為成員函數(shù),另一個(運算符左側(cè)不是對象名的)作為友元函數(shù)。但不可能將兩個都作為成員函數(shù),原因是顯然的。C++規(guī)定,有的運算符(如賦值運算符、下標運算符、函數(shù)調(diào)用運算符)必須定義為類的成員函數(shù),有的運算符那么不能定義為類的成員函數(shù)(如流插入“<<〞和流提取運算符“>>〞、類型轉(zhuǎn)換運算符)。由于友元的使用會破壞類的封裝,因此從原那么上說,要盡量將運算符函數(shù)作為成員函數(shù)。但考慮到各方面的因素,一般將單目運算符重載為成員函數(shù),將雙目運算符重載為友元函數(shù)。在學習了本章第10.7節(jié)例10.9的討論后,讀者對此會有更深入的認識。說明:有的C++編譯系統(tǒng)(如VisualC++6.0)沒有完全實現(xiàn)C++標準,它所提供不帶后綴.h的頭文件不支持把成員函數(shù)重載為友元函數(shù)。上面例10.3程序在GCC中能正常運行,而在VisualC++6.0中會編譯出錯。但是VisualC++所提供的老形式的帶后綴.h的頭文件可以支持此項功能,因此可以將程序頭兩行修改如下,即可順利運行:#include<iostream.h>以后如遇到類似情況,亦可照此辦理。雙目運算符(或稱二元運算符)是C++中最常用的運算符。雙目運算符有兩個操作數(shù),通常在運算符的左右兩側(cè),如3+5,a=b,i<10等。在重載雙目運算符時,不言而喻在函數(shù)中應該有兩個參數(shù)。下面再舉一個例子說明重載雙目運算符的應用。10.5重載雙目運算符例10.4定義一個字符串類String,用來存放不定長的字符串,重載運算符“==〞,“<〞和“>〞,用于兩個字符串的等于、小于和大于的比較運算。為了使讀者便于理解程序,同時也使讀者了解建立程序的步驟,下面分幾步來介紹編程過程。(1)先建立一個String類:#include<iostream>usingnamespacestd;classString{public:String(){p=NULL;}//默認構(gòu)造函數(shù)String(char*str);//構(gòu)造函數(shù)voiddisplay();private:char*p;//字符型指針,用于指向字符串};String∷String(char*str)//定義構(gòu)造函數(shù){p=str;}//使p指向?qū)崊⒆址畍oidString∷display()//輸出p所指向的字符串{cout<<p;}intmain(){Stringstring1(″Hello″),string2(″Book″);string1.display();cout<<endl;string2.display();return0;}運行結(jié)果為HelloBook(2)有了這個根底后,再增加其他必要的內(nèi)容?,F(xiàn)在增加對運算符重載的局部。為便于編寫和調(diào)試,先重載一個運算符“>〞。程序如下:#include<iostream>#include<string>usingnamespacestd;classString{public:String(){p=NULL;}String(char*str);friendbooloperator>(String&string1,String&string2);//聲明運算符函數(shù)為友元函數(shù)voiddisplay();private:char*p;//字符型指針,用于指向字符串};String∷String(char*str){p=str;}voidString∷display()//輸出p所指向的字符串{cout<<p;}booloperator>(String&string1,String&string2)//定義運算符重載函數(shù){if(strcmp(string1.p,string2.p)>0)returntrue;elsereturnfalse;}intmain(){Stringstring1(″Hello″),string2(″Book″);cout<<(string1>string2)<<endl;}程序運行結(jié)果為1。這只是一個并不很完善的程序,但是,已經(jīng)完成了實質(zhì)性的工作了,運算符重載成功了。其他兩個運算符的重載如法炮制即可。(3)擴展到對3個運算符重載。在String類體中聲明3個成員函數(shù):friendbooloperator>(String&string1,String&string2);friendbooloperator<(String&string1,String&string2);friendbooloperator==(String&string1,String&string2);在類外分別定義3個運算符重載函數(shù):booloperator>(String&string1,String&string2)//對運算符“>〞重載{if(strcmp(string1.p,string2.p)>0)returntrue;elsereturnfalse;}booloperator<(String&string1,String&string2)//對運算符“<〞重載{if(strcmp(string1.p,string2.p)<0)returntrue;elsereturnfalse;}booloperator==(String&string1,String&string2)//對運算符“==〞重載{if(strcmp(string1.p,string2.p)==0)returntrue;elsereturnfalse;}再修改主函數(shù):intmain(){Stringstring1(″Hello″),string2(″Book″),string3(″Computer″);cout<<(string1>string2)<<endl;//比較結(jié)果應該為truecout<<(string1<string3)<<endl;//比較結(jié)果應該為falsecout<<(string1==string2)<<endl;//比較結(jié)果應該為falsereturn0;}運行結(jié)果為100結(jié)果顯然是對的。到此為止,主要任務根本完成。(4)再進一步修飾完善,使輸出結(jié)果更直觀。下面給出最后的程序。#include<iostream>usingnamespacestd;classString{public:String(){p=NULL;}String(char*str);friendbooloperator>(String&string1,String&string2);friendbooloperator<(String&string1,String&string2);friendbooloperator==(String&string1,String&string2);voiddisplay();private:char*p;};String∷String(char*str){p=str;}voidString∷display()//輸出p所指向的字符串{cout<<p;}booloperator>(String&string1,String&string2){if(strcmp(string1.p,string2.p)>0)returntrue;elsereturnfalse;}booloperator<(String&string1,String&string2){if(strcmp(string1.p,string2.p)<0)returntrue;elsereturnfalse;}booloperator==(String&string1,String&string2){if(strcmp(string1.p,string2.p)==0)returntrue;elsereturnfalse;}voidcompare(String&string1,String&string2){if(operator>(string1,string2)==1){string1.display();cout<<″>″;string2.display();}elseif(operator<(string1,string2)==1){string1.display();cout<<″<″;string2.display();}elseif(operator==(string1,string2)==1){string1.display();cout<<″=″;string2.display();}cout<<endl;}intmain(){Stringstring1(″Hello″),string2(″Book″),string3(″Computer″),string4(″Hello″);compare(string1,string2);compare(string2,string3);compare(string1,string4);return0;}運行結(jié)果為Hello>BookBook<ComputerHello==Hello增加了一個compare函數(shù),用來對兩個字符串進行比較,并輸出相應的信息。這樣可以減輕主函數(shù)的負擔,使主函數(shù)簡明易讀。通過這個例子,不僅可以學習到有關(guān)雙目運算符重載的知識,而且還可以學習怎樣去編寫C++程序。這種方法的指導思想是:先搭框架,逐步擴充,由簡到繁,最后完善。邊編程,邊調(diào)試,邊擴充。千萬不要企圖在一開始時就解決所有的細節(jié)。類是可擴充的,可以一步一步地擴充它的功能。最好直接在計算機上寫程序,每一步都要上機調(diào)試,調(diào)試通過了前面一步再做下一步,步步為營。這樣編程和調(diào)試的效率是比較高的。讀者可以試驗一下。單目運算符只有一個操作數(shù),如!a,-b,&c,*p,還有最常用的++i和--i等。重載單目運算符的方法與重載雙目運算符的方法是類似的。但由于單目運算符只有一個操作數(shù),因此運算符重載函數(shù)只有一個參數(shù),如果運算符重載函數(shù)作為成員函數(shù),那么還可省略此參數(shù)。下面以自增運算符“++〞為例,介紹單目運算符的重載。10.6重載單目運算符例10.5有一個Time類,包含數(shù)據(jù)成員minute(分)和sec(秒),模擬秒表,每次走一秒,滿60秒進一分鐘,此時秒又從0開始算。要求輸出分和秒的值。#include<iostream>usingnamespacestd;classTime{public:Time(){minute=0;sec=0;}//默認構(gòu)造函數(shù)Time(intm,ints):minute(m),sec(s){}//構(gòu)造函數(shù)重載Timeoperator++();//聲明運算符重載函數(shù)voiddisplay(){cout<<minute<<″:″<<sec<<endl;}//定義輸出時間函數(shù)private:intminute;intsec;};TimeTime∷operator++()//定義運算符重載函數(shù){if(++sec>=60){sec-=60;//滿60秒進1分鐘++minute;}return*this;//返回當前對象值}intmain(){Timetime1(34,0);for(inti=0;i<61;i++){++time1;time1.display();}return0;}運行情況如下:34:134:2┆34:5935:035:1(共輸出61行)可以看到:在程序中對運算符“++〞進行了重載,使它能用于Time類對象?!?+〞和“--〞運算符有兩種使用方式,前置自增運算符和后置自增運算符,它們的作用是不一樣的,在重載時怎樣區(qū)別這二者呢?針對“++〞和“--〞這一特點,C++約定:在自增(自減)運算符重載函數(shù)中,增加一個int型形參,就是后置自增(自減)運算符函數(shù)。例10.6在例10.5程序的根底上增加對后置自增運算符的重載。修改后的程序如下:#include<iostream>usingnamespacestd;classTime{public:Time(){minute=0;sec=0;}Time(intm,ints):minute(m),sec(s){}Timeoperator++();//聲明前置自增運算符“++〞重載函數(shù)Timeoperator++(int);//聲明后置自增運算符“++〞重載函數(shù)voiddisplay(){cout<<minute<<″:″<<sec<<endl;}private:intminute;intsec;};TimeTime∷operator++()//定義前置自增運算符“++〞重載函數(shù){if(++sec>=60){sec-=60;++minute;}return*this;//返回自加后的當前對象}TimeTime∷operator++(int)//定義后置自增運算符“++〞重載函數(shù){Timetemp(*this);sec++;if(sec>=60){sec-=60;++minute;}returntemp;//返回的是自加前的對象}intmain(){Timetime1(34,59),time2;cout<<″time1:″;time1.display();++time1;cout<<″++time1:″;time1.display();time2=time1++;//將自加前的對象的值賦給time2cout<<″time1++:″;time1.display();cout<<″time2:″;time2.display();//輸出time2對象的值}請注意前置自增運算符“++〞和后置自增運算符“++〞二者作用的區(qū)別。前者是先自加,返回的是修改后的對象本身。后者返回的是自加前的對象,然后對象自加。請仔細分析后置自增運算符重載函數(shù)。運行結(jié)果如下:time1:34:59(time1原值)++time1:35:0(執(zhí)行++time1后time1的值)time1++:35:1(再執(zhí)行time1++后time1的值)time2:35:0(time2保存的是執(zhí)行time1++前time1的值)可以看到:重載后置自增運算符時,多了一個int型的參數(shù),增加這個參數(shù)只是為了與前置自增運算符重載函數(shù)有所區(qū)別,此外沒有任何作用。編譯系統(tǒng)在遇到重載后置自增運算符時,會自動調(diào)用此函數(shù)。C++的流插入運算符“<<〞和流提取運算符“>>〞是C++在類庫中提供的,所有C++編譯系統(tǒng)都在類庫中提供輸入流類istream和輸出流類ostream。cin和cout分別是istream類和ostream類的對象。在類庫提供的頭文件中已經(jīng)對“<<〞和“>>〞進行了重載,使之作為流插入運算符和流提取運算符,能用來輸出和輸入C++標準類型的數(shù)據(jù)。因此,在本書前面幾章中,但凡用“cout<<〞和“cin>>〞對標準類型數(shù)據(jù)進行輸入輸出的,都要用#include<iostream>把頭文件包含到本程序文件中。10.7重載流插入運算符和流提取運算符用戶自己定義的類型的數(shù)據(jù),是不能直接用“<<〞和“>>〞來輸出和輸入的。如果想用它們輸出和輸入自己聲明的類型的數(shù)據(jù),必須對它們重載。對“<<〞和“>>〞重載的函數(shù)形式如下:istream&operator>>(istream&,自定義類&);ostream&operator<<(ostream&,自定義類&);即重載運算符“>>〞的函數(shù)的第一個參數(shù)和函數(shù)的類型都必須是istream&類型,第二個參數(shù)是要進行輸入操作的類。重載“<<〞的函數(shù)的第一個參數(shù)和函數(shù)的類型都必須是ostream&類型,第二個參數(shù)是要進行輸出操作的類。因此,只能將重載“>>〞和“<<〞的函數(shù)作為友元函數(shù)或普通的函數(shù),而不能將它們定義為成員函數(shù)。在程序中,人們希望能用插入運算符“<<〞來輸出用戶自己聲明的類的對象的信息,這就需要重載流插入運算符“<<〞。例10.7在例10.2的根底上,用重載的“<<〞輸出復數(shù)。#include<iostream>usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}Complexoperator+(Complex&c2);//運算符“+〞重載為成員函數(shù)friendostream&operator<<(ostream&,Complex&);//運算符“<<〞重載為友元函數(shù)private:10.7.1重載流插入運算符“<<〞doublereal;doubleimag;};ComplexComplex∷operator+(Complex&c2)//定義運算符“+〞重載函數(shù){returnComplex(real+c2.real,imag+c2.imag);}ostream&operator<<(ostream&output,Complex&c)//定義運算符“<<〞重載函數(shù){output<<″(″<<c.real<<″+″<<c.imag<<″i)″<<endl;returnoutput;}intmain(){Complexc1(2,4),c2(6,10),c3;c3=c1+c2;cout<<c3;return0;}(在VisualC++6.0環(huán)境下運行時,需將第一行改為#include<iostream.h>,并刪去第2行。)運行結(jié)果為(8+14i)可以看到在對運算符“<<〞重載后,在程序中用“<<〞不僅能輸出標準類型數(shù)據(jù),而且可以輸出用戶自己定義的類對象。用“cout<<c3〞即能以復數(shù)形式輸出復數(shù)對象c3的值。形式直觀,可讀性好,易于使用。下面對怎樣實現(xiàn)運算符重載作一些說明。程序中重載了運算符“<<〞,運算符重載函數(shù)中的形參output是ostream類對象的引用,形參名output是用戶任意起的。分析main函數(shù)最后第二行:cout<<c3;運算符“<<〞的左面是cout,前面已提到cout是ostream類對象?!?lt;<〞的右面是c3,它是Complex類對象。由于已將運算符“<<〞的重載函數(shù)聲明為Complex類的友元函數(shù),編譯系統(tǒng)把“cout<<c3〞解釋為operator<<(cout,c3)即以cout和c3作為實參,調(diào)用下面的operator<<函數(shù):ostream&operator<<(ostream&output,Complex&c){output<<″(″<<c.real<<″+″<<c.imag<<″i)″<<endl;returnoutput;}調(diào)用函數(shù)時,形參output成為cout的引用,形參c成為c3的引用。因此調(diào)用函數(shù)的過程相當于執(zhí)行:cout<<″(″<<c3.real<<″+″<<c3.imag<<″i)″<<endl;returncout;請注意:上一行中的“<<〞是C++預定義的流插入符,因為它右側(cè)的操作數(shù)是字符串常量和double類型數(shù)據(jù)。執(zhí)行cout語句輸出復數(shù)形式的信息。然后執(zhí)行return語句。請思考:returnoutput的作用是什么?答復是能連續(xù)向輸出流插入信息。output是ostream類的對象,它是實參cout的引用,也就是cout通過傳送地址給output,使它們二者共享同一段存儲單元,或者說output是cout的別名。因此,returnoutput就是returncout,將輸出流cout的現(xiàn)狀返回,即保存輸出流的現(xiàn)狀。請問返回到哪里?剛剛是在執(zhí)行cout<<c3;在cout<<c3的返回值是cout的當前值。如果有以下輸出:cout<<c3<<c2;先處理cout<<c3,即(cout<<c3)<<c2;而執(zhí)行(cout<<c3)得到的結(jié)果就是具有新內(nèi)容的流對象cout,因此,(cout<<c3)<<c2相當于cout(新值)<<c2。運算符“<<〞左側(cè)是ostream類對象cout,右側(cè)是Complex類對象c2,那么再次調(diào)用運算符“<<〞重載函數(shù),接著向輸出流插入c2的數(shù)據(jù)?,F(xiàn)在可以理解了為什么C++規(guī)定運算符“<<〞重載函數(shù)的第一個參數(shù)和函數(shù)的類型都必須是ostream類型的引用,就是為了返回cout的當前值以便連續(xù)輸出。請讀者注意區(qū)分什么情況下的“<<〞是標準類型數(shù)據(jù)的流插入符,什么情況下的“<<〞是重載的流插入符。如cout<<c3<<5<<endl;有下劃線的是調(diào)用重載的流插入符,后面兩個“<<〞不是重載的流插入符,因為它的右側(cè)不是Complex類對象而是標準類型的數(shù)據(jù),是用預定義的流插入符處理的。還有一點要說明:在本程序中,在Complex類中定義了運算符“<<〞重載函數(shù)為友元函數(shù),因此只有在輸出Complex類對象時才能使用重載的運算符,對其他類型的對象是無效的。如cout<<time1;//time1是Time類對象,不能使用用于Complex類的重載運算符C++預定義的運算符“>>〞的作用是從一個輸入流中提取數(shù)據(jù),如“cin>>i;〞表示從輸入流中提取一個整數(shù)賦給變量i(假設(shè)已定義i為int型)。重載流提取運算符的目的是希望將“>>〞用于輸入自定義類型的對象的信息。10.7.2重載流提取運算符“>>〞例10.8在例10.7的根底上,增加重載流提取運算符“>>〞,用“cin>>〞輸入復數(shù),用“cout<<〞輸出復數(shù)。#include<iostream>usingnamespacestd;classComplex{public:friendostream&operator<<(ostream&,Complex&);//聲明重載運算符“<<〞friendistream&operator>>(istream&,Complex&);//聲明重載運算符“>>〞private:doublereal;doubleimag;};ostream&operator<<(ostream&output,Complex&c)//定義重載運算符“<<〞{output<<″(″<<c.real<<″+″<<c.imag<<″i)″;returnoutput;}istream&operator>>(istream&input,Complex&c)//定義重載運算符“>>〞{cout<<″inputrealpartandimaginarypartofcomplexnumber:″;input>>c.real>>c.imag;returninput;}intmain(){Complexc1,c2;cin>>c1>>c2;cout<<″c1=″<<c1<<endl;cout<<″c2=″<<c2<<endl;return0;}運行情況如下:inputrealpartandimaginarypartofcomplexnumber:36↙inputrealpartandimaginarypartofcomplexnumber:410↙c1=(3+6i)c2=(4+10i)以上運行結(jié)果無疑是正確的,但并不完善。在輸入復數(shù)的虛部為正值時,輸出的結(jié)果是沒有問題的,但是虛部如果是負數(shù),就不理想,請觀察輸出結(jié)果。inputrealpartandimaginarypartofcomplexnumber:36↙inputrealpartandimaginarypartofcomplexnumber:4-10↙c1=(3+6i)c2=(4+-10i)根據(jù)先調(diào)試通過,最后完善的原那么,可對程序作必要的修改。將重載運算符“<<〞函數(shù)修改如下:ostream&operator<<(ostream&output,Complex&c){output<<″(″<<c.real;if(c.imag>=0)output<<″+″;//虛部為正數(shù)時,在虛部前加“+〞號output<<c.imag<<″i)″<<endl;//虛部為負數(shù)時,在虛部前不加“+〞號returnoutput;}這樣,運行時輸出的最后一行為c2=(4-10i)。通過本章前面幾節(jié)的討論,可以看到:在C++中,運算符重載是很重要的、很有實用意義的。它使類的設(shè)計更加豐富多彩,擴大了類的功能和使用范圍,使程序易于理解,易于對對象進行操作,它表達了為用戶著想、方便用戶使用的思想。有了運算符重載,在聲明了類之后,人們就可以像使用標準類型一樣來使用自己聲明的類。類的聲明往往是一勞永逸的,有了好的類,用戶在程序中就不必定義許多成員函數(shù)去完成某些運算和輸入輸出的功能,使主函數(shù)更加簡單易讀。好的運算符重載能表達面向?qū)ο蟪绦蛟O(shè)計思想。在本章的例子中讀者應當注意到,在運算符重載中使用引用(reference)的重要性。利用引用作為函數(shù)的形參可以在調(diào)用函數(shù)的過程中不是用傳遞值的方式進行虛實結(jié)合,而是通過傳址方式使形參成為實參的別名,因此不生成臨時變量(實參的副本),減少了時間和空間的開銷。此外,如果重載函數(shù)的返回值是對象的引用時,返回的不是常量,而是引用所代表的對象,它可以出現(xiàn)在賦值號的左側(cè)而成為左值(leftvalue),可以被賦值或參與其他操作(如保存cout流的當前值以便能連續(xù)使用“<<〞輸出)。但使用引用時要特別小心,因為修改了引用就等于修改了它所代表的對象。在C++中,某些不同類型數(shù)據(jù)之間可以自動轉(zhuǎn)換,例如inti=6;i=7.5+i;編譯系統(tǒng)對7.5是作為double型數(shù)處理的,在求解表達式時,先將6轉(zhuǎn)換成double型,然后與7.5相加,得到和為13.5,在向整型變量i賦值時,將13.5轉(zhuǎn)換為整數(shù)13,然后賦給i。這種轉(zhuǎn)換是由C++編譯系統(tǒng)自動完成的,用戶不需干預。這種轉(zhuǎn)換稱為隱式類型轉(zhuǎn)換。10.8不同類型數(shù)據(jù)間的轉(zhuǎn)換
10.8.1標準類型數(shù)據(jù)間的轉(zhuǎn)換C++還提供顯式類型轉(zhuǎn)換,程序人員在程序中指定將一種指定的數(shù)據(jù)轉(zhuǎn)換成另一指定的類型,其形式為類型名(數(shù)據(jù))如int(89.5)其作用是將89.5轉(zhuǎn)換為整型數(shù)89。對于用戶自己聲明的類型,編譯系統(tǒng)并不知道怎樣進行轉(zhuǎn)換。解決這個問題的關(guān)鍵是讓編譯系統(tǒng)知道怎樣去進行這些轉(zhuǎn)換,需要定義專門的函數(shù)來處理。轉(zhuǎn)換構(gòu)造函數(shù)(conversionconstructorfunction)的作用是將一個其他類型的數(shù)據(jù)轉(zhuǎn)換成一個類的對象。先回憶一下以前學習過的幾種構(gòu)造函數(shù):默認構(gòu)造函數(shù)。以Complex類為例,函數(shù)原型的形式為Complex();//沒有參數(shù)用于初始化的構(gòu)造函數(shù)。函數(shù)原型的形式為Complex(doubler,doublei);//形參表列中一般有兩個以上參數(shù)用于復制對象的復制構(gòu)造函數(shù)。函數(shù)原型的形式為10.8.2轉(zhuǎn)換構(gòu)造函數(shù)Complex(Complex&c);//形參是本類對象的引用現(xiàn)在又要介紹一種新的構(gòu)造函數(shù)——轉(zhuǎn)換構(gòu)造函數(shù)。轉(zhuǎn)換構(gòu)造函數(shù)只有一個形參,如Complex(doubler){real=r;imag=0;}其作用是將double型的參數(shù)r轉(zhuǎn)換成Complex類的對象,將r作為復數(shù)的實部,虛部為0。用戶可以根據(jù)需要定義轉(zhuǎn)換構(gòu)造函數(shù),在函數(shù)體中告訴編譯系統(tǒng)怎樣去進行轉(zhuǎn)換。在類體中,可以有轉(zhuǎn)換構(gòu)造函數(shù),也可以沒有轉(zhuǎn)換構(gòu)造函數(shù),視需要而定。以上幾種構(gòu)造函數(shù)可以同時出現(xiàn)在同一個類中,它們是構(gòu)造函數(shù)的重載。編譯系統(tǒng)會根據(jù)建立對象時給出的實參的個數(shù)與類型選擇形參與之匹配的構(gòu)造函數(shù)。使用轉(zhuǎn)換構(gòu)造函數(shù)將一個指定的數(shù)據(jù)轉(zhuǎn)換為類對象的方法如下:〔1〕先聲明一個類?!?〕在這個類中定義一個只有一個參數(shù)的構(gòu)造函數(shù),參數(shù)的類型是需要轉(zhuǎn)換的類型,在函數(shù)體中指定轉(zhuǎn)換的方法?!?〕在該類的作用域內(nèi)可以用以下形式進行類型轉(zhuǎn)換:類名(指定類型的數(shù)據(jù))就可以將指定類型的數(shù)據(jù)轉(zhuǎn)換為此類的對象。不僅可以將一個標準類型數(shù)據(jù)轉(zhuǎn)換成類對象,也可以將另一個類的對象轉(zhuǎn)換成轉(zhuǎn)換構(gòu)造函數(shù)所在的類對象。如可以將一個學生類對象轉(zhuǎn)換為教師類對象,可以在Teacher類中寫出下面的轉(zhuǎn)換構(gòu)造函數(shù):Teacher(Student&s){num=s.num;strcpy(name,);sex=s.sex;}但應注意:對象s中的num,name,sex必須是公用成員,否那么不能被類外引用。用轉(zhuǎn)換構(gòu)造函數(shù)可以將一個指定類型的數(shù)據(jù)轉(zhuǎn)換為類的對象。但是不能反過來將一個類的對象轉(zhuǎn)換為一個其他類型的數(shù)據(jù)(例如將一個Complex類對象轉(zhuǎn)換成double類型數(shù)據(jù))。C++提供類型轉(zhuǎn)換函數(shù)(typeconversionfunction)來解決這個問題。類型轉(zhuǎn)換函數(shù)的作用是將一個類的對象轉(zhuǎn)換成另一類型的數(shù)據(jù)。如果已聲明了一個Complex類,可以在Complex類中這樣定義類型轉(zhuǎn)換函數(shù):operatordouble(){returnreal;}類型轉(zhuǎn)換函數(shù)的一般形式為10.8.3類型轉(zhuǎn)換函數(shù)operator類型名(){實現(xiàn)轉(zhuǎn)換的語句}在函數(shù)名前面不能指定函數(shù)類型,函數(shù)沒有參數(shù)。其返回值的類型是由函數(shù)名中指定的類型名來確定的。類型轉(zhuǎn)換函數(shù)只能作為成員函數(shù),因為轉(zhuǎn)換的主體是本類的對象。不能作為友元函數(shù)或普通函數(shù)。從函數(shù)形式可以看到,它與運算符重載函數(shù)相似,都是用關(guān)鍵字operator開頭,只是被重載的是類型名。double類型經(jīng)過重載后,除了原有的含義外,還獲得新的含義(將一個Complex類對象轉(zhuǎn)換為double類型數(shù)據(jù),并指定了轉(zhuǎn)換方法)。這樣,編譯系統(tǒng)不僅能識別原有的double型數(shù)據(jù),而且還會把Complex類對象作為double型數(shù)據(jù)處理。那么程序中的Complex類對具有雙重身份,既是Complex類對象,又可作為double類型數(shù)據(jù)。Complex類對象只有在需要時才進行轉(zhuǎn)換,要根據(jù)表達式的上下文來決定。轉(zhuǎn)換構(gòu)造函數(shù)和類型轉(zhuǎn)換運算符有一個共同的功能:當需要的時候,編譯系統(tǒng)會自動調(diào)用這些函數(shù),建立一個無名的臨時對象(或臨時變量)。例10.9使用類型轉(zhuǎn)換函數(shù)的簡單例子。#include<iostream>usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}operatordouble(){returnreal;}//類型轉(zhuǎn)換函數(shù)private:doublereal;doubleimag;};intmain(){Complexc1(3,4),c2(5,-10),c3;doubled;d=2.5+c1;//要求將一個double數(shù)據(jù)與Complex類數(shù)據(jù)相加cout<<d<<endl;return0;}分析:(1)如果在Complex類中沒有定義類型轉(zhuǎn)換函數(shù)operatordouble,程序編譯將出錯。(2)如果在main函數(shù)中加一個語句:c3=c2;由于賦值號兩側(cè)都是同一類的數(shù)據(jù),是可以合法進行賦值的,沒有必要把c2轉(zhuǎn)換為double型數(shù)據(jù)。(3)如果在Complex類中聲明了重載運算符“+〞函數(shù)作為友元函數(shù):Complexoperator+(Complexc1,Complexc2)//定義運算符“+〞重載函數(shù){returnComplex(c1.real+c2.real,c1.imag+c2.imag);}假設(shè)在m
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 養(yǎng)鵝回收合同范本
- sushe裝修合同范例
- 代開勞務合同范本
- 高校音樂廳的運營管理探究
- ktv公主合同范本
- 包棚銷售合同范本
- 產(chǎn)品交易居間合同范例
- 住宅賣房合同范本
- 對乙方有利租房合同范本
- 個體施工合同范本
- 01-衛(wèi)生法學與衛(wèi)生法概述課件
- 汽車智能制造技術(shù)課件
- 中醫(yī)外治法課件
- 2025屆山東省濱州市三校聯(lián)考語文高三第一學期期末質(zhì)量跟蹤監(jiān)視試題含解析
- 道路運輸企業(yè)主要負責人和安全生產(chǎn)管理人員安全考核題(公共部分題+專業(yè)部分題)及答案
- 4.2 歌曲《牧羊女》課件(14張)
- 2023電化學儲能電站消防安全標準鉛炭電池(鉛酸電池)
- 2024都市人群科學護肝白皮書-byhealthx庶正康訊x天貓-202409
- 2024至2030年中國天津市酒店行業(yè)市場發(fā)展現(xiàn)狀及投資方向研究報告
- 新教材-外研版高中英語選擇性必修第二冊全冊教學課件(按單元排序-)
- 甘肅省臨夏州2023-2024學年高二下學期期末質(zhì)量檢測語文試卷(無答案)
評論
0/150
提交評論