




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、第四章編譯時(shí)多態(tài)性封裝性是面向?qū)ο蟪绦蛟O(shè)計(jì)的基礎(chǔ),可以說沒有封裝性就沒有面向?qū)ο蟮某绦蛟O(shè)計(jì)。封裝性從根本上解 決了數(shù)據(jù)的安全性,為實(shí)現(xiàn)不同數(shù)據(jù)的操作同一性奠 定了基礎(chǔ),這種操作的同一性反映了客觀世界中規(guī)范不同對象行為的需要,它了面向?qū)ο蟪绦蛟O(shè)計(jì)多態(tài)性的一部分。不過這種多態(tài)性必須預(yù)先確定操作所施加的數(shù)據(jù)類型,因此不是完備意義上的多態(tài)性,而 只是基于對象的多態(tài)性。這種不同數(shù)據(jù)的操作同一性 必須在程序編譯時(shí)靜態(tài)確定,故稱為編譯時(shí)多態(tài)性, 或稱為靜態(tài)多態(tài)性。實(shí)現(xiàn)這種靜態(tài)多態(tài)性的途徑是: 函數(shù)重載和運(yùn)算符重載。4.1 函數(shù)重載函數(shù)重載為實(shí)現(xiàn)不同數(shù)據(jù)的操作同一性提供了根本 編程機(jī)制。函數(shù)重載的基本規(guī)則:
2、函數(shù)名必須相同:體現(xiàn)了操作同一性。 函數(shù)的參數(shù)必須不同:體現(xiàn)了同一操作的實(shí)現(xiàn)差異和所施加的數(shù)據(jù)差異。在面向?qū)ο蟮某绦蛑泻瘮?shù)重載表現(xiàn)在兩個(gè)方面: 類外全局函數(shù)重載 類成員函數(shù)重載4.1.1 類外全局函數(shù)重載在面向?qū)ο蟪绦蛟O(shè)計(jì)中,全局函數(shù)常常用來作為類 的友元函數(shù),因此全局函數(shù)重載可以用來實(shí)現(xiàn)不同類對象的同一類外操作。關(guān)于全局函數(shù)重載的方法已經(jīng)在第二章中講述,本章不再贅述。為了進(jìn)一步理解函數(shù)重載是如何在編譯時(shí)確定同一操作施加于不同類型的數(shù)據(jù),我們模擬分析 C+ 編譯器如何采用“名子壓延”的方法實(shí)現(xiàn)重載函數(shù)的調(diào)用。所謂“名子壓延”是指編譯器編譯重載函數(shù)調(diào)用時(shí),先將原重載函數(shù)名和參數(shù)類型結(jié)合起來,以創(chuàng)
3、建新重 載函數(shù)名。然后用新重載函數(shù)名替代原重載函數(shù)名。例如,一個(gè)程序中有兩個(gè)重載函數(shù),原型為:int myAns(float x, int j); int myAns(int I, char c);編譯時(shí),編譯器首先壓延修改這兩個(gè)重載函數(shù)名。修改后的新函數(shù)名或許會變成如下形式:int myAnsFLTINT(float x, int j); int myAnsINTCHAR(int i, char c);這樣,就把原來無法區(qū)來的相同的函數(shù)名變成可以區(qū)分的不同的函數(shù)名。例如:調(diào)用 myAns(float x, int j) 時(shí),則調(diào)用 myAnsFLTINT(float x, int j); 而
4、調(diào)用 myAns(int I, char c) 時(shí),則調(diào)用 myAnsINTCHAR(int i, char c)。假如調(diào)用這兩個(gè)函數(shù)的語句為:exam1 = myAns(15.3, 15); exam2 = myAns(45, 'a');用新函數(shù)名替代原函數(shù)名后,使得調(diào)用這兩個(gè)函數(shù)的語句會發(fā)生如下相應(yīng)的改變:exam1 = myAnsFLTINT(15.3, 15);exam2 = myAnsINTCHAR(45, 'a');4.1.2 類成員函數(shù)重載類成員函數(shù)重載分為兩類:1 構(gòu)造函數(shù)重載為類對象的創(chuàng)建和類對象的數(shù)據(jù)成員賦初值提供不 同的方法。重載構(gòu)造函數(shù)的
5、參數(shù)必須不同。2 公有成員函數(shù)重載提供響應(yīng)相同消息的不同接口方法。這類重載有兩 種情況: 同一類中的重載成員函數(shù)的參數(shù)必須有差別。 派生類中分屬于基類和派生類的重載成員函數(shù)的參數(shù)可以相同,但基類的重載成員函數(shù)被覆蓋。 例如:class point int x, y;public:point(int a, int b) x = a; y = b; float area() return 0.0; ;class circle:public point int radius;public:circle(int x, int y, int rad):point(x, y) radius = rad;
6、float area()/ 重載成員函數(shù)return float(3.1416)*float(radius)*float(radius); ;main()point p(20, 20);circle c(8, 8, 30);cout << p.area() << endl; cout << c.area() << endl;cout << c.point:area() << endl;return 0;其中 area 是參數(shù)相同的重載成員函數(shù)。編譯過程中區(qū)別這兩個(gè)不同版本的 area 的情況有兩種: 使用對象名只能分別調(diào)用
7、基類和派生類的參數(shù)相同的重載成員函數(shù)。例如:p.area() 將調(diào)用 point:area() 方法;c.area() 將調(diào)用 circle:area 方法。在對象名后添加 “基類名:”可以使用派生類對象名可以調(diào)用基類的參數(shù)相同的重載成員函數(shù)。例如:c.point:area() 將調(diào)用 point:area() 方法。4.2 運(yùn)算符重載運(yùn)算符可以視為是一種特殊的函數(shù),它們可以用一 種簡潔的,接近自然語言的表達(dá)式方式被調(diào)用。C+ 擁有一系列的預(yù)定義運(yùn)算符,這些運(yùn)算符能對所有的預(yù)定義類型的數(shù)據(jù)進(jìn)行操作。也就是說,可以 使用預(yù)定義類型的數(shù)據(jù)作參數(shù)調(diào)用這些運(yùn)算符函數(shù)。 例如,加運(yùn)算符 "+&
8、quot;:int x, y; float e, f; y = x + y;f = e + f;這種對于不同類型的數(shù)據(jù)使用相同的表達(dá)式調(diào)用相同的運(yùn)算符正是通過重載機(jī)制實(shí)現(xiàn)的。但這些運(yùn)算符卻 不能自動施加在自定義類型的對象。例如:自定義的 復(fù)數(shù)類 complex 的定義如下:class complexdouble real, imag; public:complex(double r = 0, double i = 0) real = r; imag = i; ;main()complexcom1(1.1, 2.2), com2(3.3, 4.4), total;total = com1 + c
9、om2; return 0;/ “+”運(yùn)算符無法對復(fù)數(shù)進(jìn)行操作很顯然,因?yàn)檫\(yùn)算符 “+”產(chǎn)生上述錯誤的操的作數(shù)據(jù)類型中不包括 complex 類型,所以編譯器就不知解決的辦法就是擴(kuò)展 “+” 運(yùn)算符操作的數(shù)據(jù)類“+”型,即為復(fù)數(shù)類complex 定義的運(yùn)算符操作。C+ 的運(yùn)算符重載方法為設(shè)計(jì)不同類對象的同一行為提供了非常有效和方便的。運(yùn)算符重載是通過對運(yùn)算符函數(shù)的重載實(shí)現(xiàn)的,運(yùn)算符函數(shù)重載的原型和定義的一般形式如下:函數(shù)類型 operator (參數(shù)表列);/ 是運(yùn)算符名的通配符號函數(shù)類型 operator (參數(shù)表列) 重載操作代碼 例如,對復(fù)數(shù)類 complex 的 “+” 運(yùn)算符重載:c
10、lass complex double real, imag;public:complex(double r = 0, double i = 0) real = r; imag = i; complex operator + (complex);complex complex:operator +(complex &c)complex sum;sum.real = real + c.real; sum.imag = imag + c.imag; return sum;4.2.1 重載運(yùn)算符的規(guī)則 C+ 不定義新的運(yùn)算符,只能對系統(tǒng)預(yù)定義運(yùn)算符進(jìn)行重載。 C+ 的預(yù)定義運(yùn)算符中重載的包括
11、:算術(shù)運(yùn)算符+、-、*、/、%關(guān)系運(yùn)算符=、!=、<、>、<=、>=邏輯運(yùn)算符|、&&、!單目運(yùn)算符+、-、*、&自增自減運(yùn)算符+、-位操作運(yùn)算符|、&、<<、>>賦值運(yùn)算符=、+=、-=、*=、/=、%=、&=、|=、=、<<=、>>=內(nèi)存管理運(yùn)算符new、delete、new、delete其他運(yùn)算符()、->、 ->*、,、不重載預(yù)定義運(yùn)算符的包括: 重載不能改變預(yù)定義運(yùn)算符函數(shù)的參數(shù)(操作數(shù))個(gè)數(shù)。雙目運(yùn)算符重載后仍為雙目運(yùn)算符,單目運(yùn) 算符重載后仍為單目運(yùn)算符。
12、重載不能改變預(yù)定義運(yùn)算符的原有優(yōu)先級。 重載不能改變預(yù)定義運(yùn)算符的原有結(jié)合律。 重載運(yùn)算符函數(shù)的參數(shù)不有缺省值。否則編譯器會認(rèn)為是改變了運(yùn)算符函數(shù)的參數(shù)個(gè)數(shù)。成員運(yùn)算符.成員指針運(yùn)算符.*名域運(yùn)算符:內(nèi)存長度運(yùn)算符sizeof條件運(yùn)算符?: 重載的運(yùn)算符必須與用戶自定義類型的對象一起使用,因此重載運(yùn)算符函數(shù)的參數(shù)中至少應(yīng)該有一個(gè)是自定義類對象或類對象的。換句話說,重載運(yùn)算符函數(shù)的參數(shù)不能全部是預(yù)定義類型對象,防止用戶修改預(yù)定義運(yùn)算符的性質(zhì)。例如:int operator +(int a, int b) return a b; 顯然,這是絕對不對于雙目運(yùn)算符,的。兩個(gè)參數(shù)都是自定義類對象,例如兩
13、個(gè)復(fù)數(shù)的加運(yùn)算;也一個(gè)參數(shù)是自定義類對象,另一個(gè)參數(shù)是預(yù)定義類型對象,例如一個(gè)復(fù)數(shù)與一個(gè)實(shí)數(shù)的加運(yùn)算。complex operator +(double d, complex& c) return complex(d + c.real, c.imag); 系統(tǒng)會為每個(gè)自定義類缺省重載了賦值運(yùn)算符“=” 和取地址運(yùn)算符“&”,其他運(yùn)算符都需要根據(jù)需要進(jìn) 行重載定義。其中: 賦值運(yùn)算符“=”用于同類對象之間的數(shù)據(jù)成員賦值操作。一般情況下,缺省重載的賦值運(yùn)算符“=”可以滿足要求,但遇到類的數(shù)據(jù)成員中包含了動態(tài) 數(shù)據(jù)指針,則使用缺省重載的賦值運(yùn)算符就可能 雖然可以任意定義重載運(yùn)算符的操
14、作功能,但應(yīng)該使重載運(yùn)算符的功能類似于被重載運(yùn)算符作用于預(yù)定義類型數(shù)據(jù)時(shí)的操作功能。 運(yùn)算符重載函數(shù)可以是運(yùn)算所施加類對象的成員函數(shù),也可以是該類的友元函數(shù),如果不需要類的私有數(shù)據(jù)成員,還可以是既非類成員函數(shù)也非友元函數(shù)的普通函數(shù)。在 Java 中雖然也不乏運(yùn)算符重載的例子,例如:String str = "hello" + "there"該表達(dá)式相當(dāng)于在 C+ 中的表達(dá)式:string str = "hello" + "there"上述表達(dá)式都是因?yàn)閷?Java 的 String 類型和 C+ 的string 類
15、型的進(jìn)行了“+” 運(yùn)算符重載的結(jié)果。但要注意的是在 Java 中不用戶進(jìn)行運(yùn)算符重載。4.3 使用成員函數(shù)重載運(yùn)算符1 使用成員函數(shù)重載運(yùn)算符的語法形式 在類定義體中要重載的運(yùn)算符成員函數(shù) type 運(yùn)算符函數(shù)類型; operator 運(yùn)算符函數(shù)名關(guān)鍵字; 要重載的運(yùn)算符名; 參數(shù)表 被重載運(yùn)算符所需要的操作數(shù)。參數(shù)個(gè)數(shù) = 運(yùn)算符所需操作數(shù)個(gè)數(shù) - 1,缺省的左操作數(shù)必須是運(yùn)算符所屬類對象。例如:class complex double real, imag; public:complex operator + (complex&); 定義運(yùn)算符成員函數(shù)例如:complex comp
16、lex:operator + (complex& com) return complex(real + com.real, imag + com.imag); 重載運(yùn)算符的使用運(yùn)算符的左操作數(shù)必須是該運(yùn)算符成員函數(shù)所屬 類的對象。 雙目運(yùn)算符例如:complex com1, com2, com3; com3 = com1 + com2;或com3 = com1.operator +(com2); 單目運(yùn)算符例如:complex com;+com; com+; 或com.operator +();com.operator +(0);2 用成員函數(shù)重載運(yùn)算符的使用實(shí)例例4-1 定義了一個(gè)表
17、達(dá)三位置的簡單類 three_d,在此類中含有三位置的坐標(biāo)。通過運(yùn)算符重載來實(shí)現(xiàn)對此類對象的 +、 和 = 運(yùn)算。注意:定義中 + 和 運(yùn)算符函數(shù)的返回值不應(yīng)是被加對象和被減對象,而 = 運(yùn)算符函數(shù)的返回值必須是被賦值的對象。這都是運(yùn)算符的操作含義所決定的。4.4 使1 使元函數(shù)重載運(yùn)算符元函數(shù)重載運(yùn)算符的語法形式 在類定義體中重載運(yùn)算符友元函數(shù) friend 友元函數(shù)關(guān)鍵字 type 運(yùn)算符函數(shù)類型; operator 運(yùn)算符函數(shù)名關(guān)鍵字; 要重載的運(yùn)算符名; 參數(shù)表 被重載運(yùn)算符所需要的操作數(shù)。參數(shù)個(gè)數(shù) = 運(yùn)算符所需操作數(shù)個(gè)數(shù)。 例如:class point int x, y; publ
18、ic:friend point operator +(point&, point&); 定義重載運(yùn)算符友元函數(shù)例如:point operator +(point& p1, point& p2) return point(p1.x + p2.x, p1.y + p2.y); 重載運(yùn)算符的使用 雙目運(yùn)算符例如:point pt1, pt2, pt3;pt3 = pt1 + pt2;或pt3 = pt1.operator +(pt2); 單目運(yùn)算符例如:point pt;+pt; pt+ 或operator +(pt);operator +(pt, 0);2 使元函數(shù)
19、重載運(yùn)算符的應(yīng)用實(shí)例例4-2 使元函數(shù)重載運(yùn)算符的方法實(shí)現(xiàn)復(fù)數(shù)的四則運(yùn)算,復(fù)數(shù)運(yùn)算規(guī)則如下:(a + bi) + (c + di) = (a + c) + (b + d)i;(a + bi) - (c + di) = (a - c) + (b - d)i;(a + bi) * (c + di) = (ac - bd) + (bc + ad)i;(a + bi) / (c + di) = (ac + bd) + (bc - ad)i)/(c2+ d2);定義一個(gè)復(fù)數(shù)類 complex,并和定義相應(yīng)的友元函數(shù),用于重載運(yùn)算符 +、-、*、/。例4-3 使元函數(shù)重載運(yùn)算符的方法實(shí)現(xiàn)集合運(yùn)算。集合可以
20、用數(shù)組或鏈表表示,在該數(shù)組或鏈表中不包含重復(fù)元素。定義整型數(shù)集合 set,元素個(gè)數(shù)用整型變量 card 表示。集合的操作包括向集合中追加元素、顯示集合的全部元素以及使元函數(shù)重載運(yùn)算符的方法實(shí)現(xiàn)的集合的主要運(yùn)算,這些運(yùn)算包含: 判定某一個(gè)元素屬于集合的運(yùn)算符 &; 判定兩個(gè)集合相等的運(yùn)算符 =; 判定兩個(gè)集合的不等于運(yùn)算符 !=; 兩個(gè)集合的交運(yùn)算符 *; 兩個(gè)集合的并運(yùn)算符 +; 判定某集合是另一集合的子集運(yùn)算符 <=; 判定某集合是另一集合的純子集運(yùn)算符 <。實(shí)例 4-3程序4.5 成員函數(shù)與友元函數(shù)重載運(yùn)算符的比較1參數(shù)數(shù)目: 雙目運(yùn)算符 重載運(yùn)算符的成員函數(shù)只有一個(gè)參
21、數(shù),用于表示表達(dá)式的右操作數(shù)。 重載運(yùn)算符的友元函數(shù)有兩個(gè)參數(shù),分別用于表達(dá)式的左、右操作數(shù) 單目運(yùn)算符 重載運(yùn)算符的成員函數(shù)無參數(shù)。 重載運(yùn)算符的友元函數(shù)帶有一個(gè)參數(shù),用于表示表達(dá)式的唯一操作數(shù)。2無論是使用成員函數(shù)還是友元函數(shù)重載的運(yùn)算符,調(diào)用它們的表達(dá)式形式是一致的,而調(diào)用它們的函數(shù)形式是有差別的。表達(dá)式形式友元函數(shù)調(diào)用形式成員函數(shù)調(diào)用形式a boperator (a, b)a. operator (b) aoperator (a)a. operator ()a operator (a, 0)a. operator (0)3大部分運(yùn)算符重載函數(shù)既可以是成員函數(shù),又可以是友元函數(shù)。究竟選擇
22、哪一種好呢?要視實(shí)際情況 和程序員的習(xí)慣。但是應(yīng)注意以下情況: 對于雙目運(yùn)算符,如果使用成員函數(shù)重載,則在有些情況下會產(chǎn)生操作數(shù)類型錯誤。例如: class complex double real, imag;public:complex operator +(double x);complex complex:operator +(double x) return complex(real + x, imag); 對 complex 的對象 com 進(jìn)行如下的 + 運(yùn)算:com = com + 100.0;由于對象 com 是 + 運(yùn)算符的左操作數(shù),所以它調(diào)用了 complex 類重載的 +
23、 運(yùn)算符,把實(shí)數(shù) 100.0 加到 com 的實(shí)部數(shù)據(jù)成員 real 上。如果按照 + 運(yùn)算符操作數(shù)的交換律,將上面的表達(dá)式寫成:com = 100.0 + com;則會引起操作數(shù)類型錯誤,無法完成表達(dá)式所要 求的操作。這是因?yàn)?complex 類 + 運(yùn)算符的左操作數(shù)是 complex 類對象,而表達(dá)式的左操作數(shù)是實(shí)數(shù),無法調(diào)用 complex 類 + 運(yùn)算符函數(shù)。如果使用兩個(gè)友元函數(shù)來替換上述 complex 類的 +運(yùn)算符重載:friend operator +(complex com, double x); friend operator +(double x, complex com
24、);complex operator +(complex com, double x) return complex(com.real + x, imag); complex operator +(double x, complex com) return complex(x + com.real, imag); 則可避免上述問題,因?yàn)橛言\(yùn)算符函數(shù)的兩個(gè) 操作數(shù)都是顯式地傳遞給運(yùn)算符函數(shù)的,能滿足 加運(yùn)算操作數(shù)的交換律。所以一般建議使元函數(shù)重載雙目運(yùn)算符,特別是期望雙目運(yùn)算符的左操作數(shù)的類型能夠隱式轉(zhuǎn)換的情況,則重載雙目運(yùn)算符必須使元函數(shù),而不能使用成員函數(shù)。 若一個(gè)運(yùn)算符需要修改其操作所施
25、加對象(特別是該對象為該運(yùn)算符的第一操作數(shù))的狀態(tài),則選擇使用成員函數(shù)重載運(yùn)算符不破壞類對象的封裝性,更符合面向?qū)ο蟪绦蛟O(shè)計(jì)的原則。4.6 自增 + 和自減 - 運(yùn)算符的重載從運(yùn)算操作的正確性考慮,使用成員函數(shù)還是使用友元函數(shù)重載自增運(yùn)算符 + 和自減運(yùn)算符 - 的效果是一致的。但從面向?qū)ο笤O(shè)計(jì)原則出發(fā),類對象的自增和自減運(yùn)算實(shí)際上是對被封裝的類數(shù)據(jù)成員依次進(jìn)行的。因此,建議使用成員函數(shù)實(shí)現(xiàn)自增運(yùn)算符 + 和自減運(yùn)算符 - 的重載。使用 + 和 - 的表達(dá)式形式分為前綴和后綴兩種形式,這兩種形式對操作數(shù)的最終修改雖然相同,但運(yùn) 算符函數(shù)的返回值不同,前綴形式返回修改后的操作數(shù),而后綴形式返回修
26、改前的操作數(shù)。例如:int i = 0, j = 0;i+; +j;cout << i <<","<< j << endl;/ 顯示1,1cout << i+ <<","<< +j << endl;/ 顯示1,2在 C+ 2.1 及以后的版本中,編譯器可以通過判別在自增或自減運(yùn)算符函數(shù)的參數(shù)列表中是否增加了一個(gè)附加的整型 int 形式參數(shù)來區(qū)分所重載的自增或自減運(yùn)算符可以用于前綴表達(dá)式還是用于后綴表達(dá)式。1自增運(yùn)算符 “+” 使用成員函數(shù)重載 原型前綴形式:類
27、名后綴形式:類名例如:class point int x, y; public:operator +();operator +(int);point operator +();point operator +(int); 定義前綴形式:類名后綴形式:類名例如:類名:operator +() 類名:operator +(int) point point:operatot +() +x,+y;return *this;point point:operatot +(int) point temp(x, y);+x,+y;return temp; 調(diào)用前綴表達(dá)式形式:+類對象名; 后綴表達(dá)式形式:類對
28、象名+; point pt;例如:+pt;pt+;/ 前綴表達(dá)式/ 后綴表達(dá)式前綴函數(shù)形式:對象名.operator +();后綴函數(shù)形式:對象名.operator +(0); point pt;例如:pt.operator +();pt.operator +(0);/ 前綴函數(shù)形式/ 后綴函數(shù)形式2自減運(yùn)算符 “-” 使用成員函數(shù)重載 原型前綴形式:類名后綴形式:類名例如:class point int x, y; public:operator -();operator -(int);point operator -();point operator -(int); 定義前綴形式:類名后綴
29、形式:類名例如:類名:operator -() 類名:operator -(int) point point:operatot -() -x,-y;return *this;point point:operatot -(int) point temp(x, y);x-, y-;return temp; 調(diào)用前綴表達(dá)式形式:-類對象名; 后綴表達(dá)式形式:類對象名-; point pt;例如:-pt;pt-;/ 前綴表達(dá)式/ 后綴表達(dá)式前綴函數(shù)形式:對象名.operator -();后綴函數(shù)形式:對象名.operator -(0); point pt;例如:pt.operator -();/ 前綴
30、函數(shù)形式pt.operator -(0); / 后綴函數(shù)形式例4-4 在 point 類中對運(yùn)算符 + 和 - 進(jìn)行重載,其操作是對 point 類的數(shù)據(jù)成員 x 和 y 分別進(jìn)行的。注意,如果在程序中沒有重載能用于后綴表達(dá)式形式的 + 和 -,則在后綴表達(dá)式形式調(diào)用 + 和- 時(shí),會出現(xiàn)編譯警告,而運(yùn)行時(shí)會以前綴表達(dá)式的結(jié)果替代后綴表達(dá)式的操作結(jié)果。4.7 調(diào)用運(yùn)算符 () 和下標(biāo)運(yùn)算符 的重載1調(diào)用運(yùn)算符“()”顧名思義,調(diào)用運(yùn)算符可以用函數(shù)調(diào)用表達(dá)式的形 式使運(yùn)算符操作所施加的對象完成任何需要的功能 操作,例如,為操作對象的各個(gè)數(shù)據(jù)成員賦值。調(diào) 用該運(yùn)算符的表達(dá)式的一般形式為:類對象名(
31、調(diào)用參數(shù)列表);可以認(rèn)為調(diào)用運(yùn)算符是一個(gè)雙目運(yùn)算符。左操作數(shù): 必須是該運(yùn)算符操作所施加的類對象。右操作數(shù): 為操作類對象所需要傳遞的一組參數(shù), 這組參數(shù)可以由任意個(gè)數(shù)、任何類型的對象組成,當(dāng)然也可以無參數(shù)。顯然,應(yīng)該使用成員函數(shù)重載調(diào)用運(yùn)算符。 原型返回類型 operator ()(調(diào)用參數(shù)列表);其中返回類型可以是任何合法類型。例如:class point int x, y;public:void operator ()(int, int); 定義返回類型 類名:operator ()(調(diào)用參數(shù)列表)例如:void point:operator ()(int x, int y)this-&
32、gt;x = x; this->y = y; 調(diào)用類對象名(調(diào)用參數(shù)列表); point pt;pt(50, 80);例如:是一個(gè)使用成員函數(shù)重載調(diào)用運(yùn)算符 “()”例4-5單的簡實(shí)例,有助于對調(diào)用運(yùn)算符定義形式、使用方法和用途的理解。注意,調(diào)用運(yùn)算符函數(shù)的右操作數(shù),調(diào)用參數(shù)列表中的參數(shù)也有缺省參數(shù)值。2下標(biāo)運(yùn)算符“”與調(diào)用運(yùn)算符相似,下標(biāo)運(yùn)算符可以用下標(biāo)表達(dá)式的形式對運(yùn)算符操作所施加對象的相關(guān)數(shù)據(jù)成員進(jìn)任何需要的和操作,例如,讀寫矩陣類對象封裝的內(nèi)部矩陣(數(shù)組)的某個(gè)指定元素。調(diào)用該運(yùn)算符的表達(dá)式的一般形式為: 類對象名下標(biāo)列表;可以認(rèn)為下標(biāo)運(yùn)算符也是一個(gè)雙目運(yùn)算符。左操作數(shù): 必須是
33、該運(yùn)算符操作所施加的類對象。右操作數(shù): 為類對象所需要傳遞的一組下標(biāo),這組下標(biāo)可以由任意個(gè)數(shù)的整型對象組成,不無下標(biāo)。顯然,應(yīng)該使用成員函數(shù)重載下標(biāo)運(yùn)算符。 原型返回類型 operator (<下標(biāo)列表>);其中返回類型可以是除 void 外的任何合法類型。例如:class Matrix double mt10, 10;public:double& operator (int, int); 定義返回類型 類名:operator (下標(biāo)列表)例如:double& Matrix:operator (int x, int y)if(x > -1 &&
34、 x < 10) && (x > -1 && x < 10) return mtx, y; 調(diào)用類對象名調(diào)用參數(shù)列表;Matrix matrix; matrix5, 8 = 38.5;例如:例4-6 是一個(gè)使用成員函數(shù)重載下標(biāo)運(yùn)算符的簡單實(shí)例,有助于對下標(biāo)運(yùn)算符定義形式、使用方法和用途的理解。 通過重載的下標(biāo)運(yùn)算符函數(shù)可以方便地私有數(shù)據(jù)成員 divisionTotals 中的每一個(gè)元素。 重載下標(biāo)運(yùn)算符 “” 時(shí),返回一個(gè) int得的,使通過重載的 “”的元素既能夠讀,也能夠?qū)憽R虼耍聵?biāo)表達(dá)式可以出現(xiàn)在賦值語句的左邊。例4-7 是一個(gè)用來處理
35、矩陣運(yùn)算操作的實(shí)例。假定有一個(gè)實(shí)數(shù)矩陣,需要對它進(jìn)行加法、減法和乘法運(yùn)算(通過重載運(yùn)算符+、-、*來實(shí)現(xiàn)),為此需要通過重載函數(shù)調(diào)用運(yùn)算符(),來返回矩陣元素,以便 在實(shí)現(xiàn)矩陣的加、減、乘運(yùn)算中使用。注意:矩陣的析構(gòu)函數(shù)matrix:matrix() if(elems) /矩陣是否不為空delete elems;elems = 0;4.8 動態(tài)內(nèi)存管理運(yùn)算符的重載用于動態(tài)內(nèi)存管理的運(yùn)算符包括 new、delete (用于單個(gè)對象的內(nèi)存分配和對象數(shù)組的內(nèi)存分配和)和 new、delete (用于)。系統(tǒng)預(yù)定義的這兩對運(yùn)算符可以適用于所有類型對象的動態(tài)內(nèi)存管理,但不能確保對所有類型對象的動態(tài)內(nèi)存管
36、理都高效,尤 其是對那些占用內(nèi)存空間小、結(jié)構(gòu)簡單的類型對象, 使用那些為了適應(yīng)復(fù)雜情況管理的時(shí)、空開銷是沒有 必要的,因此大大降低運(yùn)行效率。解決這一問題的辦 法就是重載動態(tài)內(nèi)存管理運(yùn)算符,定義適應(yīng)類型對象 動態(tài)創(chuàng)建和撤消的內(nèi)存管理操作。重載動態(tài)內(nèi)存管理運(yùn)算符的方式有兩種: 全局方式:重載的動態(tài)內(nèi)存管理運(yùn)算符完全替代了原有的動態(tài)內(nèi)存管理運(yùn)算符 new、delete、new、delete 。這種方式一般很少使用,除非確實(shí)需要修改原來的通用管理算法或添加所有類型對象創(chuàng)建和撤消都需要的附加操作。 局部方式:重載的運(yùn)算符函數(shù)只對某個(gè)特定類對象的創(chuàng)建和撤消有效,這是重載動態(tài)內(nèi)存管理運(yùn)算符的常用方式。顯然,
37、將動態(tài)內(nèi)存管理運(yùn)算符重載函數(shù)定義為成員函數(shù)更符合面向?qū)ο蟪绦蛟O(shè)計(jì)原則。重載 new 和 delete 運(yùn)算符的一般方法: 定義可以存放 n 個(gè)被管理類型對象的靜態(tài)數(shù)組,作為動態(tài)分配的內(nèi)備。 定義空閑鏈,將被回收的對象內(nèi)存鏈結(jié)起來。 定義指示變量,用于指示作為內(nèi)空間是否已經(jīng)被初次順序分配完。備的靜態(tài)數(shù)組 重載動態(tài)內(nèi)存分配運(yùn)算符 new,用于順序從靜態(tài)數(shù)組中或從空閑鏈中為動態(tài)創(chuàng)建的對象分配空間。 重載動態(tài)內(nèi)存回收運(yùn)算符 delete,用于動態(tài)創(chuàng)建的對象,并將該被閑鏈中。對象的內(nèi)存空間鏈結(jié)到空例4-8 定義適用于 point 類對象動態(tài)創(chuàng)建和撤消的內(nèi)存管理運(yùn)算符 new 和 delete 重載成員函
38、數(shù),并測試使用重載的 new 和 delete 動態(tài)創(chuàng)建和撤消 point類對象的情況。注意,此例中重載的 new 和 delete 運(yùn)算符每次只能為單個(gè) point 類對象分配和內(nèi)存 ,而如果分配和point 類對象數(shù)組則需要重載 new 和 delete 運(yùn)算符。1問題分析分配一個(gè)具有足夠空間靜態(tài)數(shù)組(數(shù)組元素的結(jié)構(gòu)應(yīng)滿足存放 point 類對象屬性和動態(tài)分配和的需要。對該數(shù)組的分配和操作示意如下:usedfree_listusedfree_listx1 x2x3y1 y2y3x1y1x2y2x3y3x4y4x4y4從數(shù)組中順序分配隨機(jī)刪除已分配元素其中:·靜態(tài)數(shù)組的元素由存放位
39、置屬性 x 和 y 的單元,以及用于存放被元素地址的指針單元組成。·靜態(tài)數(shù)據(jù)成員used 用于指示從靜態(tài)數(shù)組中已經(jīng)被初次順序分配的元素個(gè)數(shù)。·靜態(tài)數(shù)據(jù)成員freelist 用于指向被鏈表。回收的元素元素的動態(tài)分配和操作分為兩種情況: 靜態(tài)數(shù)組中的元素未被初次順序分配完,即 used的值小于靜態(tài)數(shù)組的元素總數(shù)時(shí)(元素第一次被 分配): 分配:以 used 的值為下標(biāo),為用戶動態(tài)分配一個(gè)元素,并修改 used 的值。:將新的元素與 freelist 指向的存放已元素的空閑鏈連接,并使 freelist 指向修改后的空閑鏈。 數(shù)組中的元素已被初次順序分配完,即 used 的值大于
40、靜態(tài)數(shù)組的元素總數(shù)時(shí)(數(shù)組中元素的再分配): 分配:如果被元素的空閑鏈不為空,則從空閑鏈中動態(tài)分配一個(gè)元素,并修改空閑鏈。:將新的元素與 freelist 指向的存放已元素的空閑鏈連接,并使 freelist 指向修改后的空閑鏈。將運(yùn)算符 new 和 delete 重載函數(shù)和定義為 point類的成員函數(shù),point 類的類圖被描述如下:2詳細(xì)設(shè)計(jì) 類設(shè)計(jì) point 類類定義class point int x, y;static int used; static block *freelist;public:point(int vx, int vy);void* operator new (
41、size_t size); void operator delete ();void print();其中,block 為用于動態(tài)定義 point 對象時(shí),分配其屬性空間的數(shù)據(jù)結(jié)構(gòu):struct block int x, y; block *next;算法描述重載運(yùn)算符 new 的算法 N-S 圖:重載運(yùn)算符 delete 的算法 N-S 圖: 類的應(yīng)用在主函數(shù) main 中動態(tài)創(chuàng)建 point 對象、顯示對象信息;然后動態(tài)動態(tài)創(chuàng)建 point 對象,用以測試重載的動態(tài)內(nèi)存管理運(yùn)算符 new 和 delete 的功能。程序編碼34.9 賦值運(yùn)算符重載類對象之間的賦值操作是在一一對應(yīng)的數(shù)據(jù)成員之
42、 間進(jìn)行的。所以賦值運(yùn)算符的重載函數(shù)應(yīng)作為類的成 員函數(shù)。賦值運(yùn)算符成員函數(shù)的原型、定義和調(diào)用表 達(dá)式如下: 原型類名operator =(const 類名&);例如:class point int x, y;public:point operator = (const point&); 定義類名 類名:operator = (const 類名&對象名)例如:point point:operator = (const point& pt)x = pt.x; y = pt.y;return *this; 調(diào)用對象名1 = 對象名2;point pt1, pt2;p
43、t2 = pt1;系統(tǒng)會為每一個(gè)類缺省定義一個(gè)隱含的賦值運(yùn)算符例如:成員函數(shù)。通常情況下,缺省賦值運(yùn)算符是可以勝任類對象之間的賦值操作,但在某些特殊情況下,如類中有指針類型的數(shù)據(jù)成員時(shí),使用缺省賦值運(yùn)算符就可能產(chǎn)生錯誤。例如:#include <iostream.h> #include <string.h> class stringchar* ptr;public:string(char* s)ptr = new charstrlen(s) + 1; strcpy(ptr, s);string() delete ptr; void print() cout <&l
44、t; ptr << endl; ;void main()string p1("Chen");string p2(“Zhang"); p2 = p1;cout << "p2:"p2.print();cout << "p1:"p1.print();在執(zhí)行 p1.print(); 時(shí)將發(fā)生錯誤。是執(zhí)行賦值語句 p2 = p1,使 p2.ptr 和 p1.ptr 都指向了 “Chen” 占用的內(nèi)存空間,而 p2.ptr存原來所指向的 “Zhang”占用的內(nèi)空間被泄漏。當(dāng) p2 的生命周期結(jié)束時(shí),系
45、統(tǒng)自動調(diào)用析構(gòu)函數(shù)將這一內(nèi)存空間撤消。這時(shí) p1 的指針成員ptr 所指向的內(nèi)存空間已經(jīng)成為不的空間了。下圖描述了p這1一動錯態(tài)誤空間產(chǎn)1 生的p2過程動:態(tài)空間2執(zhí)行 p2 = p1 之前執(zhí)行 p2 = p1 之后P2 生命周期結(jié)束后解決這一問題的方法是顯式地定義一個(gè)重載賦值運(yùn)算符的成員函數(shù),使 p1 和 p2 有各自的string& operator = (const string&);string& string:operator = (const string& s)空間。if (this = &s) return *this;if (ptr)
46、delete ptr;/ 類對象自身賦值/原有動態(tài)內(nèi)存指針ptr = new charstrlen(s.ptr) + 1;/ 為賦值操作分配新內(nèi)存strcpy(ptr, s.ptr);return *this;/ 賦值字符串值/ 返回被賦值的類對象兩點(diǎn)說明: 重載類的賦值運(yùn)算符應(yīng)該使用成員函數(shù),而不應(yīng)使元函數(shù),如果上述賦值運(yùn)算符重載使用了友元函數(shù):friend string& operator = (string& p2, string& p1);這時(shí),表達(dá)式p1 = "chen"將被解釋為operator = (p1, "chen&quo
47、t;)這顯然是沒有什麼問題的,但對于表達(dá)式"chen" = p1將被解釋為:/ 錯誤的賦值語句operator = ("chen", p1)C+ 編譯器首先將 “chen”即string轉(zhuǎn)換成一個(gè)隱含的對象,然后該隱含對象。因此并不認(rèn)為這個(gè)表達(dá)式是錯誤的,從而將導(dǎo)致賦值語法的。 類的賦值運(yùn)算符可以被重載,但重載的賦值運(yùn)算符成員函數(shù)在其派生類中是不能被繼承的。建議:在屬性的操作上,重載賦值運(yùn)算符和拷貝構(gòu)造函數(shù)具有一致性。因此,在需要用戶自定義重載賦值運(yùn)算符和拷貝構(gòu)造函數(shù)的情況下,一般先定義一個(gè)實(shí)現(xiàn)屬性操作的私有成員函數(shù),然后在重載賦值運(yùn)算符和拷貝構(gòu)造函數(shù)定
48、義中調(diào)用此私有成員函數(shù)。這樣既保證了重載賦值運(yùn)算符和拷貝構(gòu)造函數(shù)的4.10 重載輸入運(yùn)算符 ">>"輸入運(yùn)算符 “>>”講是輸入流類(將在第八章中詳細(xì)述)的成員函數(shù)。該運(yùn)算符也是一個(gè)雙目運(yùn)算符,它的左操作數(shù)必須是輸入流類對象的,表示被輸入的信息必須來自標(biāo)準(zhǔn)的輸入流設(shè)備;而右操作數(shù)是接收輸入信息的指定類對象的。因此,為自定義類重載的輸入運(yùn)算符函數(shù)只能是類的友元函數(shù)。1原型friend 輸入流類&operator >> (輸入流類&,類名&);例如:class pointint x, y;public:friend i
49、stream& operator >> (istream&, point&);2定義輸入流& operator >>(輸入流&流對象名, 類名& 對象名)return 流對象名;例如:istream& operator >> (istream& in, point& pt);cout << “順序輸入點(diǎn)的位置坐標(biāo) x 和 y:”;in >> pt.x >> pt.y; return in;3調(diào)用cin >> 類對象名;例如:point pt
50、;cin >> pt;注意: 輸入運(yùn)算符重載函數(shù)的第一個(gè)參數(shù)的類型必須是輸入流類 istream 對象的,形參名(流對象名)可以使用任何合法的標(biāo)識符。 輸入運(yùn)算符重載函數(shù)的第二個(gè)參數(shù)的類型必須是接收輸入信息的指定類對象的,例如 point&, 而不能使用指定類名,例如 point。 輸入運(yùn)算符重載函數(shù)的返回類型必須是輸入流類istream 對象的的輸入流類對象的,并且在函數(shù)體中由 return 返回名必須與第一個(gè)參數(shù)的形參名(流對象名)一致。4.11 重載輸出運(yùn)算符 “<<"輸出運(yùn)算符 “<<”講是輸出流類(將在第八章中詳細(xì)述)的成員函數(shù)。
51、該運(yùn)算符也是一個(gè)雙目運(yùn)算符,它的左操作數(shù)必須是輸出流類對象的,表示信息必須被輸出到標(biāo)準(zhǔn)的輸出流設(shè)備;而右操作數(shù)是輸出信息的指定類對象。因此,為自定義類重載的輸入運(yùn)算符函數(shù)也只能是類的友元函數(shù)。1原型friend 輸出流類&operator << (輸出流類&,類名);例如:class pointint x, y;public:friend istream& operator >> (istream&, point&); friend ostream& operator << (ostream&, poi
52、nt);2定義輸出流& operator <<(輸出流&流對象名, 類名 對象名)return 流對象名;例如:ostream& operator << (ostream& out, point pt);out << “點(diǎn)的位置坐標(biāo) x 和 y:”;out << pt.x << “,” <<return out;pt.y << endl;3調(diào)用cout << 類對象名;例如:point pt;cin >> pt;cout << pt;注意: 輸
53、出運(yùn)算符重載函數(shù)的第一個(gè)參數(shù)的類型必須是輸出流類 ostream 對象的,形參名(流對象名)可以使用任何合法的標(biāo)識符。 輸出運(yùn)算符重載函數(shù)的第二個(gè)參數(shù)的類型必須是輸出信息的指定類對象或?qū)ο蟮幕?point。,例如 point&, 輸出運(yùn)算符重載函數(shù)的返回類型必須是輸出流類ostream 對象的的輸出流類對象的,并且在函數(shù)體中由 return 返回名必須與第一個(gè)參數(shù)的形參名(流對象名)一致。例8-3 中對輸入運(yùn)算符 >> 和輸出運(yùn)算符 << 進(jìn)行了重載,使它們能對按照指定形式(例如由實(shí)部和虛部組成的代數(shù)和形式,20 + 35i )表示的復(fù)數(shù)進(jìn)行標(biāo)準(zhǔn)輸入輸出操作。例8-4 中對輸入運(yùn)算符 >> 和輸出運(yùn)算符 << 進(jìn)行了重載,使它們能對按照指定形式(例如由分母組成的分?jǐn)?shù)形式,3/8) 表示的有理數(shù)進(jìn)行標(biāo)準(zhǔn)輸入輸出操作。4.12 類型轉(zhuǎn)換所謂類型轉(zhuǎn)換是指編譯器將一種數(shù)據(jù)類型值轉(zhuǎn)換
溫馨提示
- 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 當(dāng)事人誠信悔過書3篇
- 代簽委托書在出口退稅中的應(yīng)用3篇
- 卷簾門安裝協(xié)議格式3篇
- 迎新生的精彩演講稿(4篇)
- 2025求職簡歷里的自我評價(jià)(11篇)
- 景區(qū)旅游信息化應(yīng)用水平提升考核試卷
- 園林綠化合同范本(4篇)
- 社會救助住宿服務(wù)滿意度調(diào)查考核試卷
- 白酒的品牌形象與市場認(rèn)可研究考核試卷
- 綠色交通與城市出行方式的投資策略與前景預(yù)測考核試卷
- 宿舍樓施工方案方案
- 甲醇-水精餾塔
- 中國話劇史專題知識
- GB/T 15544.1-2023三相交流系統(tǒng)短路電流計(jì)算第1部分:電流計(jì)算
- GB/T 90.3-2010緊固件質(zhì)量保證體系
- GB/T 18799-2020家用和類似用途電熨斗性能測試方法
- 科技公司涉密計(jì)算機(jī)軟件安裝審批表
- GA/T 1369-2016人員密集場所消防安全評估導(dǎo)則
- GA 1517-2018金銀珠寶營業(yè)場所安全防范要求
- FZ/T 64014-2009膜結(jié)構(gòu)用涂層織物
- 高考試卷命題設(shè)計(jì)的技巧 課件24張
評論
0/150
提交評論