C++類中的運算符重載過程
為什么要實現(xiàn)運算符重載?
在 C++ 中,運算符最初是為內(nèi)置類型(如int
、double
等)定義操作方式。當定義一個新的類(自定義類型)時,編譯器并不清楚如何對這個新類型的成員變量應(yīng)用運算符。
通過運算符重載,程序員可以明確地告訴編譯器對于該類的對象,運算符(如+
、-
、*
等)應(yīng)該如何操作其成員變量,從而使自定義類型能夠像內(nèi)置類型一樣自然地使用這些運算符。
1.加法運算符重載
作用:實現(xiàn)兩個自定義類型數(shù)據(jù)的加法運算
在類內(nèi)實現(xiàn)加法運算符重載
#include <iostream> using namespace std; class Person { int age; int money; public: Person() : money(0), age(0) {} Person(int val, int val2) : age(val), money(val2) {} Person(const Person& other) { this->age = other.age; this->money = other.money; } // 類內(nèi)實現(xiàn)+重載 本質(zhì):Person p3=p1.operator+(p2) Person operator+(const Person& other) { Person p; p.age = this->age + other.age; p.money = this->money + other.money; return p; // 不以引用返回是因為,在執(zhí)行完這個函數(shù)后,p會被銷毀,以值傳遞會調(diào)用拷貝構(gòu)造 } void print() { cout << age << " " << money << endl; } }; int main() { Person a(18, 50); // 括號法 Person b = {12, 50}; // 隱式轉(zhuǎn)換法 Person c = a + b; c.print(); return 0; }
實現(xiàn)加法運算符重載的operator+函數(shù)來完成的,傳入的參數(shù)為const Person& other的原因有以下的兩點:
- 1.以引用的方式傳遞是為了防止調(diào)用拷貝構(gòu)造
- 2.加const修飾是為了防止修改實參
在函數(shù)中聲明了一個Person的對象p,返回值是以值的形式返回,因為值返回會調(diào)用拷貝構(gòu)造,如果是以引用的方式傳遞,當這個函數(shù)結(jié)束時,對象p就會被銷毀掉。
在類外實現(xiàn)加法運算符重載
#include <iostream> using namespace std; class Person { int age; int money; friend Person operator+(const Person& other1, const Person& other2); public: Person() : money(0), age(0) {} Person(int val, int val2) : age(val), money(val2) {} Person(const Person& other) { this->age = other.age; this->money = other.money; } void print() { cout << age << " " << money << endl; } }; // 類外實現(xiàn)+重載 本質(zhì):Person p3=operator+(p1,p2) Person operator+(const Person& other1, const Person& other2) { Person p; p.age = other1.age + other2.age; p.money = other1.money + other2.money; return p; } int main() { Person a(18, 50); // 括號法 Person b = {12, 50}; // 隱式轉(zhuǎn)換法 Person c = a + b; c.print(); return 0; }
在類外實現(xiàn)加法運算符重載,相當于類外函數(shù)訪問類內(nèi)的成員變量,所以要將這個函數(shù)在類中聲明為友元函數(shù)(friend)。其他的跟在類內(nèi)實現(xiàn)加法運算符重載是一樣的。
本質(zhì):在類內(nèi)實現(xiàn)加法運算符重載的本質(zhì)是:Person p3=p1.operator(p2)
在類外實現(xiàn)加法運算符重載的本質(zhì)是:Person p3=operator+(p1,p2)
因為一個是通過對象去調(diào)用這個函數(shù),它本身也算是一個參數(shù),所以只需要傳人一個參數(shù)。而在類外,則是相當于直接調(diào)用這個函數(shù),所以傳入的參數(shù)是兩個。
無論是再類內(nèi)還是在類外實現(xiàn)加法運算符重載,最后調(diào)用的方式都是+。
2.左移運算符重載
作用:可以輸出自定義數(shù)據(jù)類型
要在類外實現(xiàn),因為在類內(nèi)的話,調(diào)用格式為:對象.operator();無法達到cout<<
#include <iostream> using namespace std; class Person { int age; int money; public: friend ostream& operator<<(ostream& o, const Person& p); Person() : age(0), money(0) {} Person(int val, int val2) : age(val), money(val2) {} Person(const Person& other) { cout << "調(diào)用拷貝構(gòu)造"; this->age = other.age; this->money = other.money; } // 一般不在函數(shù)內(nèi)進行左移重載 /*void operator<<(ostream& cout,const Person p) { }*/ }; // 類外實現(xiàn)左移運算符重載 ostream& operator<<(ostream& o, const Person& p) { o << p.age << " " << p.money << endl; return o; } int main() { Person a(5, 12), b; cout << a << b << endl; return 0; }
因為是在類外實現(xiàn)的,所以在類內(nèi)要將其設(shè)置為友元函數(shù)。參數(shù)為兩個,一個為ostream類型的o,另外一個為引用類型的對象。
返回值為引用類型的ostream類型的ostream,因為如果想要進行連續(xù)的輸出,就必須讓前一個的結(jié)果作為第二個左移運算符的第一個參數(shù),如下圖:
在o<<p.age的返回值為o,然后它與后面就變成了o<<" ",接著又調(diào)用這個運算符,這樣才能完成連續(xù)的輸出。
3.遞增運算符重載
遞增分為兩種一種是前++,一種是后++。前++是在使用之前就讓這個數(shù)加1,返回的是加1之后的結(jié)果。而后++是先返回這個數(shù)再進行加一操作。
前++返回的是引用,后++返回的是值。
#include <iostream> using namespace std; class Person { int age; int money; public: Person() : age(0), money(0) {} Person(int val, int val2) : age(val), money(val2) {} Person(const Person& other) { this->age = other.age; this->money = other.money; } // 前置++的重載 返回引用 Person& operator++() { // 保證是對一個數(shù)進行++ this->age++; this->money++; return *this; } // 后置++的重載 加一個int參數(shù)占位符區(qū)分 返回值 Person operator++(int) { Person temp = *this; // 用一個局部變量返回++之前的結(jié)果 this->age++; this->money++; return temp; } void print() { cout << age << " " << money; } }; int main() { Person p(5, 12); ++p; p.print(); return 0; }
對前++和后++都是operator++,所以為了區(qū)分,對于后++來說,需要加一個參數(shù)占位符來進行區(qū)分。
在返回值這塊,前++返回的是引用,因為要的是它進行加一之后的結(jié)果,所以可以直接返回這個對象。
而后++則返回的是一個值,因為要返回的是它加一之前的結(jié)果,所以需要一個局部變量返回++之前的結(jié)果。
4.+=運算符重載
#include <iostream> using namespace std; class Person { int age; int money; public: friend ostream& operator<<(ostream& o, const Person& p); Person() : age(0), money(0) {} Person(int val, int val2) : age(val), money(val2) {} Person(const Person& other) { this->age = other.age; this->money = other.money; } Person& operator+=(const Person& other) { this->age += other.age; this->money += other.money; return *this; } void print() { cout << age << " " << money; } }; ostream& operator<<(ostream& o, const Person& p) { o << p.age << " " << p.money << endl; return o; } int main() { Person a(1, 1), b(2, 2), c(3, 3); a += b += c; cout << a << b << c; return 0; }
+=運算符的返回值也是對象本身,因為會涉及到連續(xù)+=的情況,和左移運算符的重載類似。
這樣才能實現(xiàn)連續(xù)+=的實現(xiàn)。如上面代碼運行的結(jié)果為:
要注意運算的順序是從右往左進行計算的。
5.關(guān)系運算符和賦值運算符重載
#include <iostream> using namespace std; class A { int num; int* p; public: A() : num(0), p(nullptr) {} A(int x) : num(x), p(new int(num)) {} A(const A& other) { this->num = other.num; } bool operator>(const A& other) { if (this->num > other.num) return 1; else return 0; } bool operator==(const A& other) { if (this->num == other.num) return 1; else return 0; } A& operator=(const A& other) { if (p) delete p; // 釋放原來的堆區(qū)內(nèi)存,拷貝構(gòu)造沒有這一步 num = other.num; p = new int(num); // 指向新的堆區(qū)內(nèi)存 return *this; } }; int& fun() { int a = 2; return a; } int main() { int x = fun(); // 行 int& y = fun(); // 不行 A a(2), b(3), c; cout << (a == b); a = b =c; // 如果類內(nèi)沒有實現(xiàn)賦值運算符,編譯器則會提供默認的賦值運算符,每個成員變量都會被賦值,此時要注意淺拷貝問題 return 0; }
關(guān)系運算符主要包括==、>、<等,他們的返回值都是bool類型。
賦值運算符,就是把other的值給調(diào)用它的對象,如果不對賦值運算符進行重載的話,那么它就會是簡單的賦值操作,這里就會導(dǎo)致淺拷貝的問題(可以看作者前面提到的淺拷貝和深拷貝問題)。所以我們就需要對它進行重載。
在上述代碼中,因為p是一塊指向堆區(qū)的指針變量,所以在進行賦值運算符重載時,需要開辟一塊新的堆區(qū),然后保證兩個堆區(qū)的內(nèi)容一樣。同時,還有保證之前這個指針變量p有沒有指向別的堆區(qū)內(nèi)容,如果有,就將它釋放,避免內(nèi)存泄漏。返回值為引用類型,返回對象本身。
注意:賦值運算符也是編譯器給一個類至少添加的函數(shù)。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
C/C++通過IP獲取局域網(wǎng)網(wǎng)卡MAC地址
這篇文章主要為大家詳細介紹了C++如何通過Win32API函數(shù)SendARP從IP地址獲取局域網(wǎng)內(nèi)網(wǎng)卡的MAC地址,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02C++中based for循環(huán)的實現(xiàn)
C++中的范圍for循環(huán)是一種簡潔的遍歷容器的方法,本文主要介紹了C++中based for循環(huán)的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2025-02-02詳解C語言數(shù)據(jù)結(jié)構(gòu)之棧
這篇文章主要為大家介紹了C語言數(shù)據(jù)結(jié)構(gòu)之棧,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01