《運算子覆載》PPT课件

上传人:hs****ma 文档编号:584145424 上传时间:2024-08-30 格式:PPT 页数:81 大小:346.50KB
返回 下载 相关 举报
《運算子覆載》PPT课件_第1页
第1页 / 共81页
《運算子覆載》PPT课件_第2页
第2页 / 共81页
《運算子覆載》PPT课件_第3页
第3页 / 共81页
《運算子覆載》PPT课件_第4页
第4页 / 共81页
《運算子覆載》PPT课件_第5页
第5页 / 共81页
点击查看更多>>
资源描述

《《運算子覆載》PPT课件》由会员分享,可在线阅读,更多相关《《運算子覆載》PPT课件(81页珍藏版)》请在金锄头文库上搜索。

1、第十四章運算子覆載1第十四章 運算子覆載在C+語言中,程式設計師除了可以對函式(包含成員函式)進行覆載之外,也可以對運算符號進行覆載,以擴充運算符號的功能,此稱為運算子覆載(Operator Overloading)。當然由於運算子分為單元運算子、二元運算子、前置運算子、後置運算子,因此運算子的覆載也比函式覆載稍微複雜一些,因此我們將運算子覆載獨立出來在本章作詳細的介紹。2大綱14.1 運算子覆載的需求14.2 運算子覆載14.3 單元運算子的覆載14.4 二元運算子的覆載14.5 單元運算與二元運算同時存在的覆載14.6 轉型運算子的覆載14.6.1物件轉基本資料型態14.6.2不同類別型態

2、間的轉換14.7 =與= =運算子覆載14.7.1=運算子覆載14.7.2=運算子覆載14.8 運算子覆載14.8.1運算子覆載14.9 本章回顧3在前面的章節中,我們使用運算子進行運算時,使用的都是運算子內定的功能,例如基本的四則運算子:加+、減-、乘*、除/,比較運算子的比較運算:大於、等於= =、小於、-等等。(2)運算子的運算可以區分為不需要回傳值及需要回傳值。若不需要回傳值,則回傳資料型態應宣告為void。回傳資料型態 operator#(傳入引數);614.2運算子覆載(3)傳入引數與函式的傳入引數類似,但有些不同。運算子的運算對象可以區分為單元運算(例如傳統的a+;)及二元運算(

3、例如傳統的a+b;)。如果是二元運算則後面的運算元(第二個運算元)需設定為引數(前面的運算元不必設定為引數,因為這是在類別內定義,因此該類別的物件將自動隱含成為第一個運算元)。如果是單元運算,則又可以分為兩種狀況,如下所述。(4)單元運算分為兩種狀況,一種是前置運算子(例如傳統的+a;),一種是後置運算子(例如傳統的a+;)。宣告前置運算子覆載時不需要指定引數,宣告後置運算子覆載時則需要設定引數為int。(5)運算子的覆載還有一些限制如下:7限制一:覆載運算子需符合C+語法。限制二:程式設計師無法新創運算子符號,只能針對C+原有的運算符號進行覆載,同時有些運算子是無法被覆載的,整理如下:14.

4、2運算子覆載可覆載的運算子+-*/%&|!=+-= =!=&= ( )-*newdelete表14-1 可進行覆載的運算子814.2 運算子覆載限制三:在可被覆載的運算子中,有些運算子只能被定義為單元運算子,如下表:限制四:在可被覆載的運算子中,有些運算子可以被定義為單元運算子或二元運算子,如下表:無法覆載的運算子.*?:sizeof表14-2 不可進行覆載的運算子只能被定義為單元運算子-+! 表14-3 只能被定義為單元運算子可被定義為單元運算子或二元運算子+-&*表14-4 可被定義為單元運算子或二元運算子914.2運算子覆載限制五:無法重新定義運算元的個數(如限制四與限制三的規定)。限制

5、六:無法重新定義運算子優先權。限制七:無法覆蓋運算子的原有功能。也就是內建的資料型態無法使用運算子覆載重新定義,例如下列語法欲重新定義兩浮點數相加是錯誤的語法。float operator+(float Y); /這是錯誤的宣告1014.2運算子覆載當宣告運算子覆載後,即可在類別外定義運算子覆載的內容,語法如下:語法說明:我們也可以將宣告與定義合併於類別內,此時就不需指定類別名稱。而事實上,覆載運算子函式也屬於該類別的一個成員函式,我們稱之為覆載函式或覆載成員函式。回傳資料型態 類別名稱:operator#(傳入引數) 定義運算子覆載的運算行為;1114.3單元運算子的覆載在本節中,我們將介紹

6、單元運算子的覆載,單元運算子分為前置運算子與後置運算子兩種,首先我們先複習第三章所介紹的前置運算子與後置運算子定義。前置運算子(例如:+i):運算元進行加一或減一的動作後,再進行其他運用。後置運算子(例如:i+):運算元先進行其他運用,再進行加一或減一的動作。對於前置運算子而言,其覆載宣告語法如下:對於後置運算子而言,其覆載宣告語法如下:回傳資料型態 operator#();回傳資料型態 operator#(int);1214.3單元運算子的覆載語法說明:(1)前置運算子覆載宣告與後置運算子覆載宣告的分別在於是否有傳入引數int(int是固定語法,無法修改為其他如float等資料型態)。(2)

7、前置運算子與後置運算子的運算內容可以不同。(3)若無回傳資料,則回傳資料型態為void,此時若前置運算子與後置運算子的行為相同,則無論是前置運算子或後置運算子都不會影響整個運算式的結果。(4)若有回傳資料,則應該宣告回傳資料的資料型態,此時前置運算子應先進行運算行為,再回傳資料;後置運算子則應回傳原有資料再進行運算行為(這需要一些技巧)。1314.3單元運算子的覆載範例:【觀念範例14-1】:宣告及定義單元運算子+的覆載,使得對自訂類別Matrix2D具有運算功能,扮演前置運算子,將進行累加2,扮演後置運算子,將進行累加3。不論是前置或後置運算子都不會回值資料。範例14-1:ch14_01.c

8、pp(檔案位於隨書光碟 ch14ch14_01.cpp)。class Matrix public: . void operator+() /覆載前置運算子 .前置運算子行為. ; void operator+(int) /覆載後置運算子 .後置運算子行為. .1412345678910111213141516171819202122232425262728293031/* 檔名:ch14_01.cpp 功能:單元運算子+的覆載 */#include #include using namespace std;class Matrix2D public: Matrix2D():a11(0),a12

9、(0),a21(0),a22(0) /建構函式將矩陣內容設定為0 void operator+() / 宣告+前置運算子覆載 a11+; a12+; a21+; a22+; a11+; a12+; a21+; a22+; ; void operator+(int) / 宣告+後置運算子覆載 a11+; a12+; a21+; a22+; a11+; a12+; a21+; a22+; a11+; a12+; a21+; a22+; ; void Display(); private: int a11,a12; int a21,a22;1514.3單元運算子的覆載323334353637 38

10、39404142434445464748495051525354void Matrix2D:Display() cout | a11 , a12 | endl; cout | a21 , a22 | endl;int main(void) Matrix2D ObjA,ObjB; +ObjA; /前置運算子 cout ObjA= endl; ObjA.Display(); cout - endl; ObjB+; /後置運算子 cout ObjB= 使用程式設計師擴充的功能,矩陣內容會加3。執行Y+; -使用C+內定的功能,將Y的數值加一。ObjA=| 2 , 2 | 2 , 2 |-ObjB=|

11、 3 , 3 | 3 , 3 |1714.3單元運算子的覆載在範例14-1中,若後置運算子也設定為矩陣內容+2,則由執行結果中,將看不出來後置運算子與前置運算子的差別,這是因為我們並要求覆載的前置或後置運算子回傳資料。事實上,如果我們讓覆載的前置或後置運算子回傳資料,也能夠讓前置運算子與後置運算子的效果有所不同。舉例來說,在C+中,若+作為前置運算子,則會先進行加一的動作後,再將結果回傳。若+作為後置運算子,則會先傳遞變數值,然後才進行加一的動作。如下圖:1814.3單元運算子的覆載圖14-2 前置運算子與後置運算子的差別1914.3單元運算子的覆載【觀念及實用範例14-2】:參考+運算子的原

12、意,覆載+的前置與後置運算子功能,使其可適用於Matrix2D類別的矩陣遞增運算。範例14-2:ch14_02.cpp(檔案位於隨書光碟 ch14ch14_02.cpp)。12345678910/* 檔名:ch14_02.cpp 功能:前置運算子與後置運算子的覆載 */#include #include using namespace std;20111213141516171819202122232425262728293031323334353637 38 39class Matrix2D public: Matrix2D():a11(0),a12(0),a21(0),a22(0) /建構

13、函式將矩陣內容設定為0 Matrix2D operator+() / 宣告+前置運算子覆載,並回傳物件 a11+; a12+; a21+; a22+; return *this; ; Matrix2D operator+(int) / 宣告+後置運算子覆載,並回傳物件 Matrix2D TempObj; TempObj=*this; a11+; a12+; a21+; a22+; return TempObj; ; void Display(); private: int a11,a12; int a21,a22;void Matrix2D:Display() cout | a11 , a12

14、 | endl; cout | a21 , a22 | endl;2114.3單元運算子的覆載4041424344454647484950515253545556int main(void) Matrix2D ObjA,ObjB,ObjC,ObjD; cout 原本ObjA= endl; ObjA.Display(); cout ObjB= endl; ObjB.Display(); cout 經ObjB=+ObjA;運算後 endl; ObjB=+ObjA; /前置運算子 cout ObjA= endl; ObjA.Display(); cout ObjB= endl; ObjB.Displ

15、ay(); cout = endl;2214.3單元運算子的覆載575859606162636465666768697071 cout 原本ObjC= endl; ObjC.Display(); cout ObjD= endl; ObjD.Display(); cout 經ObjD=ObjC+;運算後 endl; ObjD=ObjC+; /後置運算子 cout ObjC= endl; ObjC.Display(); cout - endl; cout ObjD= endl; ObjD.Display(); /system(pause); return 0;2314.3單元運算子的覆載執行結果:

16、範例說明:(1)第1519行是+前置運算子的覆載定義。它會回傳一個Matrix2D類別的物件,由於前置運算子的原意是先進行運算再回傳運算結果,因此,回傳時只要將原本物件內容回傳即可,因此,我們透過this指標達成這項工作。(2)第2026行是+後置運算子的覆載定義。雖然後置運算子的原意和前置運算子的原意恰好相反,但我們卻無法單純地將第17、18行的順序對調作為覆載運算定義,因為這會先遇到return而造成遞增運算未被執行,故我們先使用TempObj存放原始矩陣內容,最後也是回傳TempObj,以符合後置運算子的原意。原本ObjA=| 0 , 0 | 0 , 0 |ObjB=| 0 , 0 |

17、0 , 0 |經ObjB=+ObjA;運算後ObjA=| 1 , 1 | 1 , 1 |ObjB=| 1 , 1 | 1 , 1 |=原本ObjC=| 0 , 0 | 0 , 0 |ObjD=| 0 , 0 | 0 , 0 |經ObjD=ObjC+;運算後ObjC=| 1 , 1 | 1 , 1 |-ObjD=| 0 , 0 | 0 , 0 |2414.4二元運算子的覆載除了少數的單元運算子,絕大多數的運算子都屬於二元運算子,也就是運算元有兩個,例如A%B的%取餘數就是一個二元運算子,其運算元有A與B兩個。在覆載二元運算子時,由於我們一定是定義在某類別內,因此,必定有一個物件是內定的運算元,在

18、傳統加法中,被加數就是那一個運算元,例如ObjA+ObjB,我們應該把+運算子覆載在ObjA的所屬類別內。除了內定的運算元外,二元運算子的另一個運算元的資料型態則必須明確定義於覆載運算子的宣告中,因此,覆載二元運算子的宣告語法如下:語法說明:(1)二元運算一般都具有回傳值,如果沒有回傳值則可將回傳資料型態設為void。(2)宣告時,變數名稱可以省略,但定義時變數名稱不可省略,而且通常該變數會在函式內被使用。回傳資料型態 operator#(另一個運算元的資料型態 變數名稱);2514.4二元運算子的覆載舉例來說,假設X、Y、Z皆是Matrix2D類別的物件,其運算子呼叫運算子覆載函式的示意圖如

19、下:圖14-3 二元運算子覆載示意圖2614.4二元運算子的覆載【觀念及實用範例14-3】:將Matrix2D矩陣類別(矩陣元素資料型態修正為double),加入二元運算子*乘法功能,乘法對象可以是矩陣,也可以是實數。其中矩陣相乘公式如下:範例14-3:ch14_03.cpp(檔案位於隨書光碟 ch14ch14_03.cpp)。12345678910/* 檔名:ch14_03.cpp 功能:二元運算子的覆載 */#include #include using namespace std;271112131415161718192021222324252627282930313233343536

20、class Matrix2D public: Matrix2D():a11(0),a12(0),a21(0),a22(0) /建構函式將矩陣內容設定為0 Matrix2D(double w,double x,double y,double z) :a11(w),a12(x),a21(y),a22(z) /本建構函式會自動對應設定各個成員變數值 ; void Display(); Matrix2D operator*(double); /矩陣*常數 Matrix2D operator*(Matrix2D); /矩陣*矩陣 private: double a11,a12; double a21,a

21、22;Matrix2D Matrix2D:operator*(double R) /矩陣*常數 Matrix2D TempObj; TempObj.a11=this-a11*R; TempObj.a12=this-a12*R; TempObj.a21=this-a21*R; TempObj.a22=this-a22*R; return TempObj;2814.4二元運算子的覆載37 383940414243444546474849505152Matrix2D Matrix2D:operator*(Matrix2D R) /矩陣*矩陣 Matrix2D TempObj; TempObj.a11

22、=this-a11*R.a11+this-a12*R.a21; TempObj.a12=this-a11*R.a12+this-a12*R.a22; TempObj.a21=this-a21*R.a11+this-a22*R.a21; TempObj.a22=this-a21*R.a12+this-a22*R.a22; return TempObj;void Matrix2D:Display() cout | a11 , a12 | endl; cout | a21 , a22 | endl;2914.4二元運算子的覆載5354555657585960616263646566676869707

23、1int main(void) Matrix2D ObjA(2,4,6,8),ObjB(1,9,4,16),ObjC,ObjD; cout ObjA= endl; ObjA.Display(); cout ObjB= endl; ObjB.Display(); cout - endl; ObjC=ObjA*3; cout ObjC=ObjA*3= endl; ObjC.Display(); ObjD=ObjA*ObjB; cout ObjD=ObjA*ObjB= endl; ObjD.Display(); /system(pause); return 0;3014.4二元運算子的覆載執行結果:

24、範例說明:(1)第20行,宣告覆載*運算子,使其能夠應用於Matrix2D類別,進行矩陣*數學常數的運算,其定義(運算行為)紀錄於第2736行。(2)第21行,宣告覆載*運算子,使其能夠應用於Matrix2D類別,進行矩陣*矩陣的運算,其定義(運算行為)紀錄於第3746行。(3)第62行會呼叫第2736行(3將會被變數R接收,而this將指向物件ObjA)進行矩陣*數學常數的運算,並將回傳值存放於ObjC中。(4)第65行會呼叫第3746行(ObjB將會被物件變數R接收,而this將指向物件ObjA)進行矩陣*矩陣的運算,並將回傳值存放於ObjD中。ObjA=| 2 , 4 | 6 , 8 |

25、ObjB=| 1 , 9 | 4 , 16 |-ObjC=ObjA*3=| 6 , 12 | 18 , 24 |ObjD=ObjA*ObjB=| 18 , 82 | 38 , 182 |3114.5 單元運算與二元運算同時存在的覆載不知讀者是否發現一個問題,單元運算的後置運算必須將傳遞引數設為int,而二元運算則必須將第二個運算元設為引數。這在允許進行單元運算及多元運算的運算子時(如-,*),是否可能會造成混淆?請回顧範例14-3的第20行,如果我們將其運算對象設為整數(int),並將運算子改為-號,請問我們想要進行的是負號單元運算子的覆載,還是減號二元運算子的覆載呢?答案其實很簡單,因為同時

26、允許進行單元運算及二元運算覆載的運算子是無法進行後置運算子覆載的,例如我們通常會以-a代表負a,而不會以a-代表負a,因此,下列語法代表宣告的是覆載-二元運算子,其引數代表第二個運算元為整數(絕對不是代表覆載-後置單元運算子)。Matrix2D operator-(int);/* 上述語法代表宣告覆載二元運算子,使其能夠進行下列運算 Matrix2D物件 = Matrix2D物件 - 整數變數 */3214.5 單元運算與二元運算同時存在的覆載在解答上述疑惑後,同一符號的單元運算覆載與多元運算覆載就變得單純多了,我們只要遵守14.2節的限制四即可。以下,我們透過範例實作-的負號覆載與減法覆載。

27、【觀念及實作範例14-4】:-的負號覆載(單元前置運算子)與減法覆載(二元運算子)。範例14-4:ch14_04.cpp(檔案位於隨書光碟 ch14ch14_04.cpp)。12345678910/* 檔名:ch14_04.cpp 功能:同時存在單元前置運算子與二元運算子的覆載 */#include #include using namespace std;331112131415161718192021222324252627282930313233343536class Matrix2D public: Matrix2D():a11(0),a12(0),a21(0),a22(0) /建構函

28、式將矩陣內容設定為0 Matrix2D(double w,double x,double y,double z) :a11(w),a12(x),a21(y),a22(z) /本建構函式會自動對應設定各個成員變數值 ; void Display(); Matrix2D operator-(); /矩陣*-1 Matrix2D operator-(Matrix2D); /矩陣-矩陣 private: double a11,a12; double a21,a22;Matrix2D Matrix2D:operator-() /矩陣*-1 Matrix2D TempObj; TempObj.a11=-1

29、*this-a11; TempObj.a12=-1*this-a12; TempObj.a21=-1*this-a21; TempObj.a22=-1*this-a22; return TempObj;3414.5 單元運算與二元運算同時存在的覆載37 38 3940414243444546474849505152Matrix2D Matrix2D:operator-(Matrix2D R) /矩陣-矩陣 Matrix2D TempObj; TempObj.a11=this-a11-R.a11; TempObj.a12=this-a12-R.a12; TempObj.a21=this-a21-

30、R.a21; TempObj.a22=this-a22-R.a22; return TempObj;void Matrix2D:Display() cout | a11 , a12 | endl; cout | a21 , a22 | endl;3514.5 單元運算與二元運算同時存在的覆載53545556575859606162636465666768697071int main(void) Matrix2D ObjA(2,4,6,8),ObjB(1,9,4,16),ObjC,ObjD; cout ObjA= endl; ObjA.Display(); cout ObjB= endl; Ob

31、jB.Display(); cout - endl; ObjC=-ObjA; cout ObjC=-ObjA= endl; ObjC.Display(); ObjD=ObjA-ObjB; cout ObjD=ObjA-ObjB= endl; ObjD.Display(); /system(pause); return 0;3614.5 單元運算與二元運算同時存在的覆載執行結果:範例說明:(1)第20行,宣告覆載-運算子的前置運算覆載,其定義(運算行為)記錄於第2736行。(2)第21行,宣告覆載-運算子的二元運算覆載,其定義(運算行為)記錄於第3746行。(3)第62行會呼叫第2736行進行矩

32、陣*(-1)的運算,並將回傳值存放於ObjC中。(4)第65行會呼叫第3746行進行矩陣-矩陣的運算,並將回傳值存放於ObjD中。ObjA=| 2 , 4 | 6 , 8 |ObjB=| 1 , 9 | 4 , 16 |-ObjC=-ObjA=| -2 , -4 | -6 , -8 |ObjD=ObjA-ObjB=| 1 , -5 | 2 , -8 |3714.6 轉型運算子的覆載()是一種非常特殊的運算子,它通常用在引數的宣告或運算式優先權的改變,在這些狀況下,它是無法被覆載的。除此之外,()若搭配某種資料型態,還可以使用在強制型別轉換,在C語言及C+語言中,強制型別轉換具有不同的語法格式,

33、假設A為整數變數,B為浮點數,欲將B的數值設定給A,C與C+的語法如下:C語法 C+語法A = (int) B; A = int(B);()的強制型別轉換不但可以轉換為基本資料型態,也可以用在轉換結構體與類別的自訂型態轉換。當()使用在強制型別轉換時,它是可以被覆載的運算子,但僅限於C+語法的型別轉換,因為運算子覆載是C+提供的功能,C語言並不存在這種能力。3814.6 轉型運算子的覆載當然,對於()的強制型別轉換需求可能有下列四種狀況:狀況一:從基本資料型別轉換為基本資料型別。這是C+原有功能,無法也不需要被覆載。狀況二:從基本資料型別轉換為自訂資料型別。這是C+原有功能,無法也不需要被覆載

34、。狀況三:從自訂資料型別轉換為基本資料型別。可以在類別內宣告為覆載。於14.6.1節中說明。狀況四:從自訂資料型別轉換為自訂資料型別。可以在類別內宣告為覆載。於14.6.2節中說明。如果現在A為浮點變數,但是B為程式設計師自行定義的向量類別物件,主要用來儲存某個向量的x與y軸的分量,我們是否能利用類似上面的轉型動作,來求出此向量的長度呢?在C+語言中,答案是可以的,我們可以利用( )運算子的覆載,讓物件也具有這種轉型功能,我們將在本節中加以說明。3914.6.1物件轉基本資料型態當我們欲將物件強制轉型為基本資料型態時,其回傳值必定是某一種指定的基本資料型態(例如float型態)。事實上,由於物

35、件包含的成員變數可能不只一個,通常我們會想要將多筆資料換算成單一筆資料,都是發生在欲求出某種具有意義的數值時才會使用,例如求出最大值max(),但基本資料型別的名稱都已經固定,因此,將物件強制轉型為基本資料型態的案例並不多見。(例如我們想要求出物件成員變數的最大值,會以成員函式max()來加以解決。)暫且不論物件轉基本資料型態的實際用途為何!C+仍提供了此一功能,其語法如下:覆載轉型運算子()的宣告語法如下(轉為基本資料型態):覆載轉型運算子()的定義語法如下(轉為基本資料型態):類別名稱:operator 欲轉換的基本資料型態( ) .轉換方式 return 欲轉換型態的變數或常數; ope

36、rator 欲轉換的基本資料型態( );4014.6.1物件轉基本資料型態語法說明:(1)宣告必須在類別內。宣告與定義可以合併在類別內,此時就不需要指定類別名稱。(2)轉換資料型態一定會有回傳值,但不需要指定回傳值的資料型態,因為回傳值的資料型態就是欲轉換的基本資料型態。(3)轉換方式可以是任何合法的程式內容,您可以直接將某個成員變數經由轉型後回傳,或經過複雜的運算後,再決定要回傳什麼資料。(4)假設物件A為float浮點數,B為Matrix2D類別的物件,下圖可說明覆載()運算子執行的過程。圖14-4 覆載強制轉型運算子()示意圖4114.6.1物件轉基本資料型態【觀念範例14-5】:覆載d

37、ouble ( )運算子,使物件也具有轉換資料的能力,其轉換過程為,取出成員變數中的最大值,並且將之乘以2倍後回傳(如果該值非double型態,則必須先將之轉型為double型態)。範例14-5:ch14_05.cpp(檔案位於隨書光碟 ch14ch14_05.cpp)。12345678910/* 檔名:ch14_05.cpp 功能:()轉型運算子的覆載一 */#include #include using namespace std;42111213141516171819202122232425262728293031323334353637class Matrix2D public: M

38、atrix2D():a11(0),a12(0),a21(0),a22(0) /建構函式將矩陣內容設定為0 Matrix2D(double w,double x,double y,double z) :a11(w),a12(x),a21(y),a22(z) /本建構函式會自動對應設定各個成員變數值 ; void Display(); operator double(); /轉型運算子覆載宣告 private: double a11,a12; double a21,a22;Matrix2D:operator double() /轉型運算子覆載定義 double max; max=this-a11;

39、 if(max a12) max=this-a12; if(max a21) max=this-a21; if(max a22) max=this-a22; return (max*2);4314.6.1物件轉基本資料型態38 394041424344454647484950515253545556void Matrix2D:Display() cout | a11 , a12 | endl; cout | a21 , a22 | endl;int main(void) Matrix2D ObjA(1.3,7.5,9.7,6.2); double X; cout ObjA= endl; Obj

40、A.Display(); X=double(ObjA); cout X= X endl; /system(pause); return 0;4414.6.1物件轉基本資料型態執行結果:範例說明:(1)第20行,宣告覆載轉型運算子(),轉型後的資料型態為double,其定義(運算行為)記錄於第2736行。(2)第51行會呼叫第2736行進行轉型,並將回傳值存放於X中。依據題意及程式內容,X將會是ObjA成員變數中最大值的兩倍。ObjA=| 1.3 , 7.5 | 9.7 , 6.2 |X=19.44514.6.2不同類別型態間的轉換類別強制轉型運算子的覆載,在物件轉物件時(兩物件隸屬不同類別)通

41、常比較有幫助,例如,我們可能希望將2x2矩陣物件轉型為3x3矩陣物件(將原有元素保留,其餘填0)。在C+中,類別轉類別型態的語法如下:覆載轉型運算子()的宣告語法如下(轉為自訂類別資料型態):覆載轉型運算子()的定義語法如下(轉為自訂類別資料型態):語法說明:語法與轉基本資料型態類似,只不過將之改為已宣告過的合法類別名稱。類別名稱:operator 欲轉換的類別資料型態( ) .轉換方式 return 欲轉換類別的物件; operator 欲轉換的類別資料型態( );4614.6.2不同類別型態間的轉換【觀念範例14-6】:覆載( )運算子,使Matrix22物件可轉換為Matrix33物件,

42、轉換後原有元素將以兩倍出現,而新元素將被設定為100。範例14-6:ch14_06.cpp(檔案位於隨書光碟 ch14ch14_06.cpp)。12345678910111213/* 檔名:ch14_06.cpp 功能:()轉型運算子的覆載二 */#include #include using namespace std;class Matrix22; /宣告有一個類別 Matrix22class Matrix33; /宣告有一個類別 Matrix334714.6.2不同類別型態間的轉換14151617181920212223242526272829class Matrix22 public:

43、 Matrix22():a11(0),a12(0),a21(0),a22(0) /建構函式將矩陣內容設定為0 Matrix22(double w,double x,double y,double z) :a11(w),a12(x),a21(y),a22(z) /本建構函式會自動對應設定各個成員變數值 ; void Display(); operator Matrix33(); /轉型運算子覆載宣告 private: double a11,a12; double a21,a22;4814.6.2不同類別型態間的轉換3031323334353637 38 394041424344454647484

44、950class Matrix33 public: Matrix33():a11(0),a12(0),a13(0),a21(0),a22(0),a23(0), a31(0),a32(0),a33(0) /建構函式將矩陣內容設定為0 Matrix33(double p11,double p12,double p13, double p21,double p22,double p23, double p31,double p32,double p33) :a11(p11),a12(p12),a13(p13), a21(p21),a22(p22),a23(p23), a31(p31),a32(p32

45、),a33(p33) /本建構函式會自動對應設定各個成員變數值 ; void Display(); private: double a11,a12,a13; double a21,a22,a23; double a31,a32,a33;4914.6.2不同類別型態間的轉換51525354555657585960616263646566676869707172Matrix22:operator Matrix33() /轉型運算子覆載定義 Matrix33 TempObj(this-a11*2,this-a12*2,100, this-a21*2,this-a22*2,100, 100, 100

46、,100); return TempObj;void Matrix22:Display() cout | a11 , a12 | endl; cout | a21 , a22 | endl;void Matrix33:Display() cout | a11 , a12 , a13 | endl; cout | a21 , a22 , a23 | endl; cout | a31 , a32 , a33 | endl;5014.6.2不同類別型態間的轉換執行結果:7374757677787980818283848586int main(void) Matrix22 ObjA(164,177,1

47、55,189); Matrix33 ObjB; cout ObjA= endl; ObjA.Display(); ObjB=Matrix33(ObjA); cout ObjB= endl; ObjB.Display(); /system(pause); return 0;ObjA=| 164 , 177 | 155 , 189 |ObjB=| 328 , 354 , 100 | 310 , 378 , 100 | 100 , 100 , 100 |5114.6.2不同類別型態間的轉換範例說明:(1)第23行,宣告覆載轉型運算子(),轉型後的資料型態為Matrix33,其定義(運算行為)記錄於第

48、5158行,其中產生TempObj物件時,會呼叫Matrix33的建構函式(第3542行)。(2)第80行會呼叫第5158行進行轉型,並將回傳值存放於ObjB中。依據題意及程式內容,ObjB的各元素將會ObjA各元素的兩倍,其餘則補100。52=運算子在C+中的原意是設定,=運算子在C+中的原意是比較是否相等,這兩個運算子的使用率極高,我們將在本節中介紹這兩個運算子的覆載。14.7 =與= =運算子覆載5314.7.1=運算子覆載在C+中,=運算子的設定功能原本就非常強大,它除了可以進行基本資料型態的設定之外,還可以進行結構體或物件的設定。一般來說,在=左右的資料型態如果相同,它都能夠準確地將

49、=右邊的資料設定給左邊的變數。如果=左右的資料型態不相同時,則會依照內定模式進行自動資料轉型(如第三章所述),通常只有基本資料型態才具有自動轉型能力,若欲將基本資料型態轉型並指定給物件,則需要在類別內覆載=運算子。覆載=運算子的宣告語法如下:覆載=運算子的定義語法如下:void 類別名稱:operator=(等號右邊的資料型態) .覆載內容void operator =(等號右邊的資料型態);5414.7.1=運算子覆載語法說明:(1)宣告必須在類別內。宣告與定義可以合併在類別內,此時就不需要指定類別名稱。而所謂類別名稱代表的是=運算子左邊的物件變數所屬的類別,例如:X=A;,則應該在X所屬類

50、別內進行上述宣告,至於A的資料型態則應該宣告在()內。(2)通常只有在運算式=左右的資料型態不同時才會作上述的覆載。但若=左右的資料型態相同時,也可以作上述的覆載,而這可能會改變了=運算子設定的原意。(3)覆載=運算子不需要回傳值,所以宣告為void,不過如果您宣告了回傳值,也不會影響程式正確性,因為該回傳值不會被使用。【觀念範例14-7】:覆載=運算子,使得能夠設定double變數給Matrix2D物件。範例14-7:ch14_07.cpp(檔案位於隨書光碟 ch14ch14_07.cpp)。5512345678910111213141516171819202122232425/* 檔名:c

51、h14_07.cpp 功能:=運算子的覆載 */#include #include using namespace std;class Matrix2D public: Matrix2D():a11(0),a12(0),a21(0),a22(0) Matrix2D(double w,double x,double y,double z) :a11(w),a12(x),a21(y),a22(z) /本建構函式會自動對應設定各個成員變數值 ; void Display(); void operator=(double); /宣告覆載=運算子 private: double a11,a12; dou

52、ble a21,a22;56262728293031323334353637 38 3940414243444546474849505152535455void Matrix2D:operator=(double R) /定義覆載=運算子 this-a11=R; this-a12=R*2; this-a21=R*3; this-a22=R*4;void Matrix2D:Display() cout | a11 , a12 | endl; cout | a21 , a22 | endl;int main(void) Matrix2D ObjA(2,4,6,8),ObjB,ObjC; doubl

53、e X=0.8; cout ObjA= endl; ObjA.Display(); ObjB=ObjA; /此處的=,將維持原設定之原意 cout ObjB=ObjA= endl; ObjB.Display(); ObjC=X; /此處的=,將使用覆載定義 cout ObjC=X= endl; ObjC.Display(); /system(pause); return 0;5714.7.1=運算子覆載執行結果範例說明:(1)第20行,宣告覆載=運算子,可適用於Matrix2D物件=double變數或常數,其定義(運算行為)記錄於第2632行,將傳入值分別*1、*2、*3、*4指定給成員變數。

54、(2)第46行ObjB=ObjA;的=維持原有設定之意。但第49行ObjC=X;的=則會呼叫第2632行的覆載行為。ObjA=| 2 , 4 | 6 , 8 |ObjB=ObjA=| 2 , 4 | 6 , 8 |ObjC=X=| 0.8 , 1.6 | 2.4 , 3.2 |58在C+中,=運算子的比較是否相等功能僅限於基本資料型態的比較,如果=的左邊是物件,則必須在類別內覆載=運算子。覆載=運算子的宣告語法如下:覆載=運算子的定義語法如下:14.7.2=運算子覆載bool 類別名稱:operator=(雙等號右邊的資料型態) .覆載內容 return true或false;bool ope

55、rator =(雙等號右邊的資料型態);5914.7.2=運算子覆載語法說明:(1)宣告必須在類別內。宣告與定義可以合併在類別內,此時就不需要指定類別名稱。而所謂類別名稱代表的是=運算子左邊的物件變數所屬的類別,例如:X=A;,則應該在X所屬類別內進行上述宣告,至於A的資料型態則應該宣告在()內。(2)在上述語法中,為了維持=運算子的原意,因此我們將回傳值資料型態設定為bool。【實用及觀念範例14-8】:覆載=比較運算子,使得能夠比較兩個物件是否相等(若成員變數完全相同,視為相等)。同時也覆載=比較運算子,使得能夠比較物件與基本資料型態是否相等(物件內的成員變數都與基本資料型態變數相同時,才

56、視為相等)。範例14-8:ch14_08.cpp(檔案位於隨書光碟 ch14ch14_08.cpp)。6012345678910111213141516171819202122232425/* 檔名:ch14_08.cpp 功能:=運算子的覆載 */#include #include using namespace std;class Matrix2D public: Matrix2D():a11(0),a12(0),a21(0),a22(0) Matrix2D(double w,double x,double y,double z) :a11(w),a12(x),a21(y),a22(z)

57、/本建構函式會自動對應設定各個成員變數值 ; bool operator=(Matrix2D); /宣告覆載=運算子 bool operator=(double); /宣告覆載=運算子 private: double a11,a12; double a21,a22;6114.7.2=運算子覆載262728293031323334353637 38 39404142bool Matrix2D:operator=(Matrix2D R) /定義覆載=運算子 if(this-a11=R.a11) & (this-a12=R.a12) & (this-a21=R.a21) & (this-a22=R.

58、a22) return true; else return false;bool Matrix2D:operator=(double R) /定義覆載=運算子 if(this-a11=R) & (this-a12=R) & (this-a21=R) & (this-a22=R) return true; else return false;6243444546474849505152535455565758596061626364656667686970int main(void) Matrix2D ObjA(2,4,6,8),ObjB(1,3,5,7),ObjC(2,4,6,8),ObjD(

59、2,2,2,2); double X=2; /- if (ObjA=ObjB) cout ObjA與ObjB相等 endl; else cout ObjA與ObjB不相等 endl; /- if (ObjA=ObjC) cout ObjA與ObjC相等 endl; else cout ObjA與ObjC不相等 endl; /- if (ObjC=X) cout ObjC與X相等 endl; else cout ObjC與X不相等 endl; /- if (ObjD=X) cout ObjD與X相等 endl; else cout ObjD與X不相等 endl; /- /system(pause

60、); return 0;6314.7.2=運算子覆載執行結果範例說明:(1)第19行,宣告覆載=運算子,可適用於Matrix2D物件= Matrix2D物件的比較,其定義(運算行為)記錄於第2633行。(2)第20行,宣告覆載=運算子,可適用於Matrix2D物件=double變數或常數,其定義(運算行為)記錄於第3441行。(3)第48、53行的比較運算式將呼叫第2633行的覆載行為。第58、63行的比較運算式將呼叫第3441行的覆載行為。ObjA與ObjB不相等ObjA與ObjC相等ObjC與X不相等ObjD與X相等6414.8運算子覆載上述介紹的覆載運算子都有一個特性,就是不需要和其他類

61、別合作即可完成。雖然我們並未介紹所有的運算子覆載,但其餘運算子的覆載技巧大多大同小異,除了本節要介紹的之外。6514.8.1運算子覆載是一個常用的運算子,通常使用於資料輸出。通常搭配輸出物件(例如:cout、ofstream類別生成之物件 等等)完成輸出資料的功能,而使用語法則通常如下格式:輸出物件 輸出資料 輸出資料 ;在上述語法中,我們可以將輸出資料指定為任何一種基本資料型態,例如整數、浮點數、字元字串等等。那麼我們是否可以將輸出資料指定為一個物件呢?答案是可以的(但需要經過覆載處理)。例如我們可以將輸出資料指定為標準函式庫提供的C+-style字串(也就是string類別衍生的物件)。明

62、顯地,C+編譯器若只引入函式庫,它將不知道如何應該輸出C+-style字串,但在引入標準函式庫後,C+編譯器便能夠了解要輸出C+-style字串的哪些資料。而這正是因為標準函式庫內覆載了string類別的運算子。6614.8.1運算子覆載看起來,我們如果想要利用ostream、ofstream等輸出類別輸出自訂類別的物件資料,只要在自訂類別中覆載運算子即可,但事實並非如此單純,因為實際負責輸出資料動作的並非只有我們自訂的類別,ostream、ofstream等輸出類別也必須能具備存取我們自行定義類別中私有資料的能力。因此,我們必須透過友誼技巧,將覆載時宣告為友誼運算子才行,換句話說,原本代表覆

63、載內容的成員函式必須被宣告為友誼函式。覆載運算子的宣告語法如下:覆載運算子的定義語法如下:ostream& operator(ostream& out,欲輸出的資料類別 輸出物件) out 輸出物件資料變數; return out;friend ostream& operator(ostream&,欲輸出的資料類別);6714.8.1運算子覆載語法說明:(1)宣告時必須加上關鍵字friend,宣告此運算子為友誼運算子(也就是該函式為友誼函式),以便存取另一個類別中的私有變數。例如運算子可能會需要存取ostream類別及欲輸出的資料類別的私有變數,當加上friend之後,覆載運算子與ostrea

64、m類別及欲輸出的資料類別將成為朋友,就能夠突破私有變數存取的限制了。(2)定義時並不需要加上類別名稱,雖然我們宣告覆載運算子是在欲輸出的資料類別中加以宣告,但由於是友誼函式,因此並不屬於任何類別。(3)在引數宣告中,我們宣告了一個ostream類別的參考物件out、以供我們使用。由於cout也屬於ostream類別的內定物件,因此,在使用out物件時,可以使用所有關於cout物件的語法,因為它們同屬同一類別。【實用及觀念範例14-9】:覆載運算子,使它具有輸出物件成員變數(含私有成員)的能力。範例14-9:ch14_09.cpp(檔案位於隨書光碟 ch14ch14_09.cpp)。681234

65、5678910111213123456789101112131415161718192021222324252627282930/* 檔名:ch14_09.cpp 功能:運算子的覆載 */#include #include using namespace std;class Matrix2D public: Matrix2D():a11(0),a12(0),a21(0),a22(0) Matrix2D(double w,double x,double y,double z) :a11(w),a12(x),a21(y),a22(z) /本建構函式會自動對應設定各個成員變數值 ; friend o

66、stream& operator(ostream&,Matrix2D); / 運算子覆載宣告 private: double a11,a12; double a21,a22;ostream& operator(ostream& out,Matrix2D R) / 運算子覆載定義 out | R.a11 , R.a12 | endl; out | R.a21 , R.a22 |; return out;6914.8.1運算子覆載執行結果:範例說明:(1)第19行,透過友誼方式宣告覆載運算子,可與ostream類別的物件合作進行輸出資料,其定義(運算行為)記錄於第2530行。(2)第36行,使用c

67、out物件時(cout物件隸屬於ostream類別)可順利輸出ObjA的資料成員(由第2530行完成此一工作)。31323334353637 38 3940int main(void) Matrix2D ObjA(1.3,7.5,9.7,6.2); cout ObjA= n ObjA 運算子覆載運算子的覆載與通常使用在資料的輸入,需要與istream類別的物件cin配合,覆載語法如下。覆載運算子的宣告語法如下:覆載運算子的定義語法如下:istream& operator(istream& in,欲輸入的資料類別& 輸入物件) in 物件輸入動作; . return 輸入物件;friend is

68、tream& operator(istream& ,欲輸入的資料類別&);7114.8.2運算子覆載語法說明:宣告時也需要宣告為友誼覆載函式,語法和相似,僅將,類別改為istream(in是隸屬於istream類別的物件)。此外,為了在呼叫覆載函式時,能夠共用記憶體以儲存資料,因此,我們必須將輸入物件採傳參考方式傳遞。【實用及觀念範例14-10】:覆載運算子,使它具有輸入物件成員變數(含私有成員)的能力。範例14-10:ch14_10.cpp(檔案位於隨書光碟 ch14ch14_10.cpp)。12345678910/* 檔名:ch14_10.cpp 功能:運算子的覆載 */#include

69、#include using namespace std;72111213141516171819202122232425262728293031323334353637 38class Matrix2D public: Matrix2D():a11(0),a12(0),a21(0),a22(0) Matrix2D(double w,double x,double y,double z) :a11(w),a12(x),a21(y),a22(z) /本建構函式會自動對應設定各個成員變數值 ; void Display(); friend istream& operator(istream&,Ma

70、trix2D&); / 運算子覆載宣告 private: double a11,a12; double a21,a22;istream& operator(istream& in,Matrix2D& R) / 運算子覆載定義 cout R.a11; cout R.a12; cout R.a21; cout R.a22; return in;7314.8.2運算子覆載執行結果:394041424344454647484950515253void Matrix2D:Display() cout | a11 , a12 | endl; cout | a21 , a22 | ObjA; cout Ob

71、jA= 運算子覆載範例說明:(1)第20行,透過友誼方式宣告覆載運算子,可與istream類別的物件合作進行輸入資料,其定義(運算行為)記錄於第2638行。(2)第48行,使用cin物件時(cin物件隸屬於istream類別)可順利輸入ObjA的資料成員(由第2638行完成此一工作)。7514.9本章回顧在本章中,我們介紹許多關於運算子覆載的技巧,並實作了許多範例,重點整理如下:(1)在C+語言中,程式設計師除了可以對函式(包含成員函式)進行覆載之外,也可以對運算符號進行覆載,以擴充運算符號的功能,此稱為運算子覆載(Operator Overloading)。(2)覆載運算子需要先在類別內宣告

72、,其宣告語法如下:(3)當宣告運算子覆載後,即可在類別外定義運算子覆載的內容,語法如下:回傳資料型態 類別名稱:operator#(傳入引數) . 定義運算子覆載的運算行為.;回傳資料型態 operator#(傳入引數);7614.9本章回顧(4)運算子的覆載有一些限制如下:限制一:覆載運算子需符合C+語法。限制二:程式設計師無法新創運算子符號,只能針對C+原有的運算符號進行覆載,同時有些運算子是無法被覆載的。詳見表14-2。限制三:在可被覆載的運算子中,有些運算子只能被定義為單元運算子。詳見表14-3。限制四:在可被覆載的運算子中,有些運算子可以被定義為單元運算子或二元運算子。詳見表14-4

73、。限制五:無法重新定義運算元的個數(如限制四與限制三的規定)。限制六:無法重新定義運算子優先權。限制七:無法覆蓋運算子的原有功能。也就是內建的資料型態無法使用運算子覆載重新定義。 7714.9本章回顧(5)對於前置運算子的覆載而言,其宣告語法如下:對於後置運算子的覆載而言,其宣告語法如下:(6)覆載二元運算子的宣告語法如下:(7)覆載轉型運算子()的宣告語法如下(轉為基本資料型態):覆載轉型運算子()的宣告語法如下(轉為自訂類別資料型態):回傳資料型態 operator#();回傳資料型態 operator#(int);回傳資料型態 operator#(另一個運算元的資料型態 變數名稱);op

74、erator 欲轉換的基本資料型態( );operator 欲轉換的類別資料型態( );7814.9本章回顧(8)覆載=運算子的宣告語法如下:(9)覆載=運算子的宣告語法如下:(10)覆載運算子,由於跨類別,因此需要透過friend宣告為友誼覆載函式。覆載運算子的宣告語法如下:覆載運算子的定義語法如下:void operator =(等號右邊的資料型態);bool operator =(雙等號右邊的資料型態);ostream& operator(ostream& out,欲輸出的資料類別 輸出物件) out 輸出物件資料變數; return out;friend ostream& operator運算子的宣告語法如下:覆載運算子的定義語法如下:istream& operator(istream& in,欲輸入的資料類別& 輸入物件) in 物件輸入動作; return 輸入物件;friend istream& operator(istream& ,欲輸入的資料類別&);80本章習題81

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号