技術(shù)交流QQ群:1027579432,歡迎你的加入!
1.Cpp中的重載運(yùn)算符和重載函數(shù)
- C++允許在同一作用域中的某個函數(shù)和運(yùn)算符指定多個定義,分別稱為函數(shù)重載和運(yùn)算符重載。重載聲明是指一個與之前已經(jīng)在該作用域內(nèi)聲明過的函數(shù)或方法具有相同名稱的聲明,但是它們的參數(shù)列表和定義(實現(xiàn))不相同。當(dāng)調(diào)用一個重載函數(shù)或重載運(yùn)算符時,編譯器通過調(diào)用使用的參數(shù)類型與定義中的參數(shù)類型進(jìn)行比較,決定選用最合適的定義。選擇最合適的重載函數(shù)或重載運(yùn)算符的過程,稱為重載決策。
2.函數(shù)重載
-
在同一個作用域內(nèi),可以聲明幾個功能類似的同名函數(shù),但是這些同名函數(shù)的形式參數(shù)(指參數(shù)的個數(shù)、類型或者順序)必須不同。您不能僅通過返回類型的不同來重載函數(shù)。函數(shù)重載的實例如下,其中print()函數(shù)就是重載函數(shù):
#include "iostream" #include "cstring" using namespace std; class A{ public: void print(int i){ cout << "整數(shù)為: " << i << endl; } void print(double d){ cout << "浮點(diǎn)數(shù)為: " << d << endl; } void print(char c[]){ cout << "字符串為: " << c << endl; } }; int main(){ A a; // 輸出整數(shù) a.print(2); // 輸出浮點(diǎn)數(shù) a.print(3.14); // 輸出字符串 char c[] = "Hello Curry"; a.print(c); cout << "----------------------------------------------\n"; return 0; } - 構(gòu)造函數(shù)可以根據(jù)參數(shù)的不同實現(xiàn)函數(shù)重載,而析構(gòu)函數(shù)沒有參數(shù),對于一個類來說也是唯一的,所以是不能重載
3.運(yùn)算符重載
- 可以重定義或重載大部分C++內(nèi)置的運(yùn)算符。這樣,就能使用自定義類型的運(yùn)算符。重載的運(yùn)算符是帶有特殊名稱的函數(shù),函數(shù)名是由關(guān)鍵字operator和其后面要重載的運(yùn)算符符號構(gòu)成的。與其他函數(shù)一樣,重載運(yùn)算符有一個返回類型和一個參數(shù)列表。例如:
Box operator+(const Box&); - 聲明加法運(yùn)算符用于把兩個Box對象相加,返回最終的Box對象。大多數(shù)的重載運(yùn)算符可被定義為普通的非成員函數(shù)或者被定義為類成員函數(shù)。如果我們定義上面的函數(shù)為類的非成員函數(shù),那么我們需要為每次操作傳遞兩個參數(shù),如下所示:
Box operator+(const Box&, const Box&); - 運(yùn)算符重載的實例,對象作為參數(shù)進(jìn)行傳遞,對象的屬性使用 this 運(yùn)算符進(jìn)行訪問,如下所示:
// 運(yùn)算符重載 class Box{ public: double getVolume(){ return length * width * height; } void setLength(int len){ length = len; } void setWidth(int wid){ width = wid; } void setHeight(int hei){ height = hei; } // 運(yùn)算符重載:用于把兩個box對象相加 Box operator+(const Box& b){ Box box; box.length = this->length + b.length; box.width = this->width + b.width; box.height = this->height + b.height; return box; } private: int length; int width; int height; }; int main(){ Box box1; Box box2; Box box3; double volume = 0.0; box1.setLength(6.0); box1.setWidth(7.0); box1.setHeight(5.0); box2.setLength(12.0); box2.setWidth(13.0); box2.setHeight(10.0); volume = box1.getVolume(); cout << "box1的體積是: " << volume << endl; volume = box2.getVolume(); cout << "box2的體積是: " << volume << endl; box3 = box1 + box2; volume = box3.getVolume(); cout << "box3的體積是: " << volume << endl; cout << "----------------------------------------------\n"; return 0; }
4.可重載運(yùn)算符與不可重載運(yùn)算符
-
可重載運(yùn)算符列表如下:
可重載運(yùn)算符.png -
不可重載運(yùn)算符列表如下:
不可重載運(yùn)算符.png
5.運(yùn)算符重載實例

運(yùn)算符重載實例.png
5.1 一元運(yùn)算符重載
- 一元運(yùn)算符只對一個操作數(shù)進(jìn)行操作,下面是一元運(yùn)算符的實例:
- ++和--運(yùn)算符重載
// ++與--運(yùn)算符重載 class Time{ private: int hours; int minutes; public: Time(){ hours = 0; minutes = 0; } Time(int h, int m): hours(h), minutes(m){ cout << "Time類對象的構(gòu)造函數(shù)\n"; } void display(){ cout << "H:" << hours << " M:" << minutes << endl; } // 重載前綴遞增++運(yùn)算符 Time operator++(){ ++minutes; // 對象加 1 if(minutes >= 60){ ++hours; minutes-= 60; } return Time(hours, minutes); } // 重載后綴遞增++運(yùn)算符 Time operator++(int){ Time T(hours, minutes); // 保存原始值 ++minutes; // 對象加 1 if(minutes >= 60){ ++hours; minutes-= 60; } return T; // 返回舊的原始值 } };- ++和--運(yùn)算符重載注意點(diǎn):
- 遞增和遞減一般是改變對象的狀態(tài),所以一般是重載為成員函數(shù)
- 重載遞增遞減,一定要和指針的遞增遞減區(qū)分開。因為這里的重載操作的是對象,而不是指針(由于指針是內(nèi)置類型,指針的遞增遞減是無法重載的),所以一般情況的遞增遞減是操作對象內(nèi)部的成員變量。
- 遞增和遞減分為前置和后置情況,a = ++b;(前置), a = b++;(后置)。因為符號一樣,所以給后置版本加一個int形參作為區(qū)分,這個形參是0,但是在函數(shù)體中是用不到的,只是為了區(qū)分前置后置。例如:
// ++與--運(yùn)算符重載注意的點(diǎn) class CA{ public: int pos; // 前置++就是增加當(dāng)前對象的pos的值,并返回當(dāng)前對象 CA operator++(){ pos++; return *this; } // 后置++就是增加當(dāng)前對象的pos的值,并返回增加pos之前的對象 CA operator++(int){ CA temp = *this; ++*this; return temp; } }; CA ca,cb; ca.pos = 1; cb = ca++; cout << "cb = " << cb.pos << endl; cb = ++ca; cout << "cb = " << cb.pos << endl;
- ++和--運(yùn)算符重載注意點(diǎn):
- 一元減運(yùn)算符,即負(fù)號(-)
// 重載一元減運(yùn)算符- class Distance{ private: int feet; int inches; public: Distance(){ feet = 0; inches = 0; } Distance(int f, int i): feet(f), inches(i){ cout << "Distance類對象的構(gòu)造函數(shù)\n"; } void displayDistance(){ cout << "F = " << feet << " I = " << inches << endl; } // 重載運(yùn)算符- Distance operator-(){ feet = -feet; inches = -inches; return Distance(feet, inches); } }; Distance D1(10, 11), D2(-5, 11); -D1; D1.displayDistance(); -D2; D2.displayDistance(); - 邏輯非運(yùn)算符(!)
- ++和--運(yùn)算符重載
5.2 二元運(yùn)算符重載
- 二元運(yùn)算符需要兩個參數(shù),下面是二元運(yùn)算符的實例。我們平常使用的加運(yùn)算符( + )、減運(yùn)算符( - )、乘運(yùn)算符( * )和除運(yùn)算符( / )都屬于二元運(yùn)算符。就像加(+)運(yùn)算符。
class Box{ public: double getVolume(){ return length * width * height; } void setLength(int len){ length = len; } void setWidth(int wid){ width = wid; } void setHeight(int hei){ height = hei; } // 運(yùn)算符重載:用于把兩個box對象相加 Box operator+(const Box& b){ Box box; box.length = this->length + b.length; box.width = this->width + b.width; box.height = this->height + b.height; return box; } private: int length; int width; int height; }; int main(){ Box box1; Box box2; Box box3; double volume = 0.0; box1.setLength(6.0); box1.setWidth(7.0); box1.setHeight(5.0); box2.setLength(12.0); box2.setWidth(13.0); box2.setHeight(10.0); volume = box1.getVolume(); cout << "box1的體積是: " << volume << endl; volume = box2.getVolume(); cout << "box2的體積是: " << volume << endl; box3 = box1 + box2; volume = box3.getVolume(); cout << "box3的體積是: " << volume << endl; cout << "----------------------------------------------\n"; return 0; }
5.3 關(guān)系運(yùn)算符重載
- C++ 語言支持各種關(guān)系運(yùn)算符( < 、 > 、 <= 、 >= 、 == 等等),它們可用于比較 C++ 內(nèi)置的數(shù)據(jù)類型,可以重載任何一個關(guān)系運(yùn)算符,重載后的關(guān)系運(yùn)算符可用于比較類的對象。
class Distance{ private: int feet; int inches; public: Distance(){ feet = 0; inches = 0; } Distance(int f, int i): feet(f), inches(i){ cout << "Distance類對象的構(gòu)造函數(shù)\n"; } void displayDistance(){ cout << "F = " << feet << " I = " << inches << endl; } // 重載關(guān)系運(yùn)算符< bool operator < (const Distance& d){ if(feet < d.feet) return true; if(feet == d.feet && inches < d.inches) return true; return false; } }; if (D1 < D2) cout << "D1 < D2\n"; else cout << "D1 > D2\n";
5.4 輸入輸出運(yùn)算符重載
- C++ 能夠使用流提取運(yùn)算符>>和流插入運(yùn)算符<<來輸入和輸出內(nèi)置的數(shù)據(jù)類型??梢灾剌d流提取運(yùn)算符和流插入運(yùn)算符來操作對象等用戶自定義的數(shù)據(jù)類型。需要把運(yùn)算符重載函數(shù)聲明為類的友元函數(shù),這樣我們就能不用創(chuàng)建對象而直接調(diào)用函數(shù)。
class Distance{ private: int feet; int inches; public: Distance(){ feet = 0; inches = 0; } Distance(int f, int i): feet(f), inches(i){ cout << "Distance類對象的構(gòu)造函數(shù)\n"; } void displayDistance(){ cout << "F = " << feet << " I = " << inches << endl; } // 重載輸入輸出運(yùn)算符 friend ostream &operator<<(ostream &output, const Distance& D){ output << "F = " << D.feet << " I = " << D.inches << endl; return output; } friend istream &operator>>(istream &input, Distance &D){ input >> D.feet >> D.inches; return input; } }; Distance D3(11, 10), D4(3, 2), D5; cout << "請輸入目標(biāo)值D5 = "; cin >> D5; cout << "D3 = " << D3 << endl; cout << "D4 = " << D4 << endl; cout << "D5 = " << D5 << endl;
5.5 賦值運(yùn)算符重載
- 像其他運(yùn)算符一樣,您可以重載賦值運(yùn)算符( = ),用于創(chuàng)建一個對象,比如拷貝構(gòu)造函數(shù)。
class Distance{ private: int feet; int inches; public: Distance(){ feet = 0; inches = 0; } Distance(int f, int i): feet(f), inches(i){ cout << "Distance類對象的構(gòu)造函數(shù)\n"; } void displayDistance(){ cout << "F = " << feet << " I = " << inches << endl; } // 賦值運(yùn)算符重載 void operator=(const Distance& D){ feet = D.feet; inches = D.inches; } }; D1 = D2; cout << "D1: " << D1 << endl; D1.displayDistance(); - 當(dāng)用用戶自定義類型變量向內(nèi)置類型變量賦值時,可以使用自定義類型的隱式轉(zhuǎn)換
class Int{ private: int n; public: Int(int i){ cout << "Int對象的構(gòu)造函數(shù)\n"; }; operator int(){ // 這里就是隱式轉(zhuǎn)換聲明,應(yīng)注意到它與運(yùn)算符重載的不同之處 return n; } }; Int int_obj(3); int i = int_obj; // 隱式調(diào)用轉(zhuǎn)換函數(shù) cout << "i = " << i << endl; cout << "int_obj = " << int_obj << endl; // 由于未重載Int的<<操作符,將隱式調(diào)用轉(zhuǎn)換函數(shù)
5.6 函數(shù)調(diào)用運(yùn)算符重載()
- 函數(shù)調(diào)用運(yùn)算符()可以被重載用于類的對象。當(dāng)重載()時,不是創(chuàng)造了一種新的調(diào)用函數(shù)的方式。相反地,這是創(chuàng)建一個可以傳遞任意數(shù)目參數(shù)的運(yùn)算符函數(shù)。
class Distance{ private: int feet; int inches; public: Distance(){ feet = 0; inches = 0; } Distance(int f, int i): feet(f), inches(i){ cout << "Distance類對象的構(gòu)造函數(shù)\n"; } void displayDistance(){ cout << "F = " << feet << " I = " << inches << endl; } // 重載函數(shù)調(diào)用運(yùn)算符 Distance operator()(int a, int b, int c){ Distance D; // 進(jìn)行隨機(jī)計算 D.feet = a + c + 10; D.inches = b + c + 100; return D; } }; Distance D6; D6 = D1(10, 10, 10); cout << "D6: " << D6 << endl;
5.7 下標(biāo)運(yùn)算符重載[]
- 下標(biāo)操作符[]通常用于訪問數(shù)組元素,重載該運(yùn)算符用于增強(qiáng)操作C++數(shù)組的功能
// 下標(biāo)運(yùn)算符重載 const int SIZE = 10; class safearray{ private: int arr[SIZE]; public: safearray(){ register int i; for(i = 0; i < SIZE; i++) arr[i] = i; } // 下標(biāo)運(yùn)算符重載 int & operator[](int i){ if(i > SIZE){ cout << "索引超過最大值: "; return arr[0]; } return arr[i]; } }; safearray sa; cout << "sa[2] = " << sa[2] << endl; cout << "sa[5] = " << sa[5] << endl; cout << "sa[12] = " << sa[12] << endl;
5.8 類成員訪問運(yùn)算符->重載
- 類成員訪問運(yùn)算符->可以被重載,但它較為麻煩。它被定義用于為一個類賦予"指針"行為。運(yùn)算符->必須是一個成員函數(shù)。如果使用了->運(yùn)算符,返回類型必須是指針或者是類的對象。運(yùn)算符->通常與指針引用運(yùn)算符*結(jié)合使用,用于實現(xiàn)"智能指針"的功能。這些指針是行為與正常指針相似的對象,唯一不同的是,當(dāng)通過指針訪問對象時,它們會執(zhí)行其他的任務(wù)。比如,當(dāng)指針銷毀時,或者當(dāng)指針指向另一個對象時,會自動刪除對象。
// 類成員訪問運(yùn)算符-> class OO{ static int i,j; public: void f() const{ // 常函數(shù) cout << i++ << endl; } void g() const{ cout << j++ << endl; } }; // 靜態(tài)成員定義 int OO::i = 10; int OO::j = 12; // 為上面的類實現(xiàn)一個容器 class ObjContainer { vector<OO*> a; public: void add(OO* obj) { a.push_back(obj); // 調(diào)用向量的標(biāo)準(zhǔn)方法 } friend class SmartPointer; }; // 實現(xiàn)智能指針,用于訪問類 Obj 的成員 class SmartPointer { ObjContainer oc; int index; public: SmartPointer(ObjContainer& objc) { oc = objc; index = 0; } // 返回值表示列表結(jié)束 bool operator++() // 前綴版本 { if(index >= oc.a.size() - 1) return false; if(oc.a[++index] == 0) return false; return true; } bool operator++(int) // 后綴版本 { return operator++(); } // 重載運(yùn)算符 -> OO* operator->() const { if(!oc.a[index]) { cout << "Zero value"; return (OO*)0; } return oc.a[index]; } }; const int sz = 10; OO o[sz]; ObjContainer oc; for(int i = 0; i < sz; i++) { oc.add(&o[i]); } SmartPointer sp(oc); // 創(chuàng)建一個迭代器 do { sp->f(); // 智能指針調(diào)用 sp->g(); } while(sp++);
6.運(yùn)算符重載注意的點(diǎn)
- a.運(yùn)算重載符不可以改變語法結(jié)構(gòu)
- b.運(yùn)算重載符不可以改變操作數(shù)的個數(shù)
- c.運(yùn)算重載符不可以改變優(yōu)先級
- d.運(yùn)算重載符不可以改變結(jié)合性
7.重載、覆蓋、隱藏(重定義)的區(qū)別:
- 重載:指的是函數(shù)具有的不同的參數(shù)列表,而函數(shù)名相同的函數(shù)。重載要求參數(shù)列表必須不同,比如參數(shù)的類型不同、參數(shù)的個數(shù)不同、參數(shù)的順序不同。如果僅僅是函數(shù)的返回值不同是沒辦法重載的,因為重載要求參數(shù)列表必須不同。(發(fā)生在同一個類里)
- 覆蓋:存在類中,子類重寫從基類繼承過來的函數(shù)。被重寫的函數(shù)不能是static的。必須是virtual的。但是函數(shù)名、返回值、參數(shù)列表都必須和基類相同。(發(fā)生在基類和子類)
- 隱藏:子類重新定義父類中有相同名稱的非虛函數(shù)(參數(shù)列表可以不同)。(發(fā)生在基類和子類)

