??????????????????????????????????????? ?食用指南:本文在有C基礎的情況下食用更佳???
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? 🍀本文前置知識:?C++類?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??今日夜電波:クリームソーダとシャンデリア—Edo_Ame江戶糖
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 1:20?━━━━━━?💟──────── 3:40
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????🔄 ? ?? ? ? ? ?? ? ???
??????????????????????????????????????💗關注👍點贊🙌收藏您的每一次鼓勵都是對我莫大的支持😍?
目錄
💓一、運算符重載基本概念
什么是運算符重載?
運算符重載簡要干貨
可重載的運算符有哪些??
💗二、前置知識-友元函數?
?什么是友元函數?
?友元函數的語法
?💞三、運算符重載
運算符重載的語法
一步一步帶你實現運算符重載(以<<為例)
運算符重載作為成員函數以及全局函數的實現(以+為例)
全局函數
成員函數
💕四、++和--運算符重載?(重要、常用)
💘具體實現用例?
一、運算符重載基本概念
什么是運算符重載?
????????運算符重載, 就是對已有的運算符重新進行定義, 賦予其另一種功能, 以適應不同
的數據類型。
????????運算符重載(operator overloading)只是一種”語法上的方便”,也就是它只是另一種函
數調用的方式。
????????在 c++中, 可以定義一個處理類的新運算符。 這種定義很像一個普通的函數定義,只是函數的名字由關鍵字 operator 及其緊跟的運算符組成。 差別僅此而已。 它像任何其他函數一樣也是一個函數, 當編譯器遇到適當的模式時, 就會調用這個函數。
運算符重載簡要干貨
????????運算符重載的目的:簡化操作 讓已有的運算符 適應適應不同的數據類型。
????????語法:函數的名字由關鍵字operator及其緊跟的運算符組成
????????比如:重載+運算符 ==>? ? ?operator+ 重載=號運算? ? ?==>? ? ?operator=
????????注意:重載運算符 不要更改 運算符的本質操作(+是數據的相加 不要重載成相減)
? ? ? ? ?栗子:(以下為重載了<<運算符的類)
class Data
{friend ostream& operator<<(ostream& out, Data& ob);//友元函數,經常與運算符重載搭配使用
private:int a;int b;
public:Data(){cout << "無參的構造函數" << endl;a = 0;b = 0;}Data(int a, int b) :a(a), b(b){cout << "有參構造" << endl;//this‐>a = a;//this‐>b = b;}void showData(void){cout << "a = " << a << ", b= " << b << endl;}~Data(){cout << "析構函數函數" << endl;}
};ostream& operator<<(ostream& out, Data& ob){out << "a = " << ob.a << ", b = " << ob.b;return out;}
? ? ? ? 解釋:
????????為了簡化類中訪問私有數據較為困難的問題,運用友元函數(下小點會提到)同重載運算符的結合,得以運用我們較為常用的<<直接輸出數據。
可重載的運算符有哪些??
????????幾乎 C 中所有的運算符都可以重載, 但運算符重載的使用時相當受限制的。 特別是不能使用 C 中當前沒有意義的運算符(例如用**求冪)不能改變運算符優先級, 不能改變運算符的參數個數。 這樣的限制有意義, 否則, 所有這些行為產生的運算符只會混淆而不是澄清寓語意。
? ? ? ? 一張圖囊括~?
二、前置知識-友元函數?
?什么是友元函數?
一句話概括:C++允許 友元 訪問 私有數據。
?友元函數的語法
friend+定義的函數
? ? ? 注意:? friend關鍵字只出現在聲明處 其他類、類成員函數、全局函數都可聲明為友元 友元函數不是類的成員,不帶this指針 友元函數可訪問對象任意成員屬性,包括私有屬性。
????????栗子: (創建一個房間類,你只準許你的朋友進入你的臥室,但是客廳是誰都可以進的)
class Room{//將goodGayVisit作為類的友元函數//goodGayVisit 訪問 類中所有數據 但是 它不是類的成員friend void goodGayVisit(Room & room);private:string bedRoom;//臥室public:string sittingRoom;//客廳public: Room(){this-> bedRoom = "臥室";this-> sittingRoom = "客廳";}};// 普通全局函數 作為 類的友元//好基友 訪問 我的房間void goodGayVisit(Room & room){cout << "好基友訪問了你的" << room.sittingRoom << endl;cout << "好基友訪問了你的" << room.bedRoom << endl;//ok}void test01(){Room myRoom;goodGayVisit(myRoom);
}
? ? ? ? friend在這里可以訪問對象任意成員屬性,包括私有屬性。因此,本來不能訪問的私有數據,在friend的情況下就可以訪問了!結果如下:
? ? ? ? 此為普通全局函數 作為 類的友元 。當然,也有類的某個成員函數 作為 另一個類的友元;一個類整體 作為 另一個類的友元等等。
????????而我們的友元函數大多應用在重載運算符上!
?????????本文僅僅對友元函數做簡單介紹,如果大家需要詳解,請在評論區或者私信踢我一腳o(╯□╰)o,作者肯定會出一篇的!
?三、運算符重載
運算符重載的語法
(根據自身改變的返回類型)operator + 重載的運算符(根據實際情況改變的傳參)
-
函數聲明:運算符重載是通過在類中定義特殊的成員函數來實現的。這些成員函數被稱為運算符重載函數。例如,如果要重載"+"運算符,則需要在類中聲明一個名為"operator+"的函數。
-
函數名:運算符重載函數的命名規則是以"operator"關鍵字開始,后面跟著要重載的運算符符號。例如,要重載"+“運算符,函數名應為"operator+”。
-
參數列表:運算符重載函數的參數列表取決于所重載的運算符。例如,對于二元運算符如"+", “-”, “*”, “/“等,參數列表應包含一個額外的參數,表示右操作數。對于一元運算符如”++”, "– – "等,參數列表不需要額外的參數。
-
返回類型:運算符重載函數的返回類型取決于所重載的運算符。例如,對于"+"運算符,返回類型通常是所操作對象的類型。
-
成員函數或友元函數:運算符重載函數可以作為類的成員函數或友元函數來定義。成員函數形式的運算符重載函數將使用對象本身作為左操作數,而友元函數形式的運算符重載函數將不使用任何對象。
一步一步帶你實現運算符重載(以<<為例)
? ? ? ? 注意:此代碼未能實現重載 下文為對用cout來輸出類的一個引入
#define _CRT_SECURE_NO_WARNINGS 01
#include <iostream>
#include<string.h>using namespace std;class Person{private:char* name;int num;public:Person(char* name, int num){this-> name = new char[strlen(name) + 1];strcpy(this-> name, name);this-> num = num;cout << "有參構造" << endl;}//普通的成員函數void printPerson(void){cout << "name = " << name << ", num = " << num << endl;}~Person(){if (this-> name != NULL){delete[] this-> name;this-> name = NULL;}cout << "析構函數" << endl;}};int main(int argc, char* argv[]){char arr[] = "lucy";Person ob1(arr, 18);//普通的成員函數 遍歷信息//ob1.printPerson();//cout默認輸出方式 無法識別 自定義對象 輸出格式cout<<ob1<<endl;//errreturn 0;}
? ? ? ? 運行改代碼,我們發現編譯器報錯!如下圖:
?????????這個時候我們就需要對運算符進行重載了!
????????那么問題又來了?如何重載運算符呢?根據上文所提到的語法,我們做出以下的操作:
????????運用operator來重載<<運算符
ostream& operator<<(ostream& out, Person& ob)//out=cout, ob =ob1{//重新實現 輸出格式out << ob.name << ", " << ob.num;//每次執行為 返回值得到coutreturn out;}
? ? ? ? 注意:ostream為cout的類型,定義ostream&為返回類型是為了作為起到鏈接的效果,如:
cout<<ob1<<ob2<<endl;ostream&返回out,然后再次被后面所調用,一直反復調用下去。
????????然而,進行了運算符重載,就能實現我們想要的效果了嗎?答案是不能,見下圖:
?????????造成這樣的原因是什么呢?還是類的封裝問題,私有的數據不能被外界所訪問!這時,我們就需要用到友元函數來幫助我們實現了!
?????????于是,我們將operator<<設置成友元:
#define _CRT_SECURE_NO_WARNINGS 01
#include <iostream>
#include<string.h>using namespace std;class Person{//設置成友元函數 在函數內 訪問Person類中的所有數據friend ostream & operator<<(ostream & out, Person & ob);private:char* name;int num;public:Person(char* name, int num){this-> name = new char[strlen(name) + 1];strcpy(this-> name, name);this-> num = num;cout << "有參構造" << endl;}//普通的成員函數void printPerson(void){cout << "name = " << name << ", num = " << num << endl;}~Person(){if (this-> name != NULL){delete[] this-> name;this-> name = NULL;}cout << "析構函數" << endl;}};ostream& operator<<(ostream& out, Person& ob)//out=cout, ob =ob1{//重新實現 輸出格式out << ob.name << ", " << ob.num;//每次執行為 返回值得到coutreturn out;}int main(int argc, char* argv[]){char arr[] = "lucy";Person ob1(arr, 18);//普通的成員函數 遍歷信息//ob1.printPerson();//cout默認輸出方式 無法識別 自定義對象 輸出格式cout<<ob1<<endl;//errreturn 0;}
? ? ? ? 實現效果如下:
運算符重載作為成員函數以及全局函數的實現(以+為例)
全局函數
????????這里同上面的栗子大致一樣,不過多敘述
#include <iostream>#include<string.h>using namespace std;class Person{//設置成友元函數 在函數內 訪問Person類中的所有數據friend ostream & operator<<(ostream & out, Person & ob);friend Person operator+(Person & ob1, Person & ob2);private:char* name;int num;public:Person(){this-> name = NULL;this-> num = 0;cout << "無參構造" << endl;}Person(char* name, int num){this-> name = new char[strlen(name) + 1];strcpy(this-> name, name);this-> num = num;cout << "有參構造" << endl;}//普通的成員函數void printPerson(void){cout << "name = " << name << ", num = " << num << endl;}~Person(){if (this-> name != NULL){delete[] this-> name;this-> name = NULL;}cout << "析構函數" << endl;}};//全局函數作為友元 完成運算符重載<<ostream & operator<<(ostream & out, Person & ob)//out=cout, ob =ob1{//重新實現 輸出格式out << ob.name << ", " << ob.num;//每次執行為 返回值得到coutreturn out;}//全局函數作為友元 完成運算符重載+Person operator+(Person & ob1, Person & ob2)//ob1 ob2{ //name+name(字符串追加)char* tmp_name = new char[strlen(ob1.name) + strlen(ob2.name) + 1];strcpy(tmp_name, ob1.name);strcat(tmp_name, ob2.name);//num+num(數值相加)int tmp_num = ob1.num + ob2.num;Person tmp(tmp_name, tmp_num);//釋放tmp_name的空間if (tmp_name != NULL){delete[] tmp_name;tmp_name = NULL;}return tmp;}void test02(){char arr[] = "lucy";Person ob1(arr, 18); char arr2[] = "bob";Person ob2(arr2, 19);cout << ob1 << endl;cout << ob2 << endl;//Person ob3 = operator+(ob1,ob2);Person ob3 = ob1 + ob2;cout << ob3 << endl;}int main(int argc, char* argv[]){test02();return 0;}
成員函數
#include <iostream>#include<string.h>using namespace std;class Person{ //設置成友元函數 在函數內 訪問Person類中的所有數據friend ostream & operator<<(ostream & out, Person & ob);private:char* name;int num;public:Person(){this-> name = NULL;this-> num = 0;cout << "無參構造" << endl;}Person(char* name, int num){this-> name = new char[strlen(name) + 1];strcpy(this-> name, name);this-> num = num;cout << "有參構造" << endl;}//成員函數 完成運算符重載 ob1用this代替 ob2用參數ob代替Person operator+(Person & ob){//this ==> &ob1//name+name(字符串追加)char* tmp_name = new char[strlen(this-> name) + strlen(ob.name) + 1];strcpy(tmp_name, this-> name);strcat(tmp_name, ob.name);//num+num(數值相加)int tmp_num = this-> num + ob.num;Person tmp(tmp_name, tmp_num);//釋放tmp_name的空間if (tmp_name != NULL){delete[] tmp_name;tmp_name = NULL;}return tmp;}//普通的成員函數void printPerson(void){cout << "name = " << name << ", num = " << num << endl;}~Person(){if (this-> name != NULL){delete[] this-> name;this-> name = NULL;}cout << "析構函數" << endl;}};//全局函數作為友元 完成運算符重載<<ostream & operator<<(ostream & out, Person & ob)//out=cout, ob =ob1{//重新實現 輸出格式out << ob.name << ", " << ob.num;//每次執行為 返回值得到coutreturn out;}void test03(){char arr[] = "lucy";char arr2[] = "bob";Person ob1(arr, 18);Person ob2(arr2, 19);//Person ob3 = ob1.operator+(ob2);Person ob3 = ob1 + ob2;cout << ob3 << endl;}int main(int argc, char* argv[]){ test03();return 0;}
? ? ? ? 在運算符重載運算符時,如果我們以成員函數的方式定義,則可以直接訪問類中的數據,無需再使用友元函數來定義。因此我們在重載運算符時最好是以成員函數的方式重載!
四、++和--運算符重載?(重要、常用)
? ? ? ? 不知道大家有沒有一個疑惑如果我們實現前置+ +、后置+ +以及前置- -、后置--,運用operator時如何區分他們呢?
? ? ? ? 此時,我們又要提到一個概念,當編譯器看到++a(前置++),它就調用operator++(a),當編譯器看到a++(后置++),它就會去調用operator++(a,int)。 - -也是同樣的道理,具體實現如下:
具體實現用例?
#include <iostream>using namespace std;class Data{friend ostream & operator<<(ostream & out, Data & ob);private:int a;int b;public:Data(){cout << "無參的構造函數" << endl;a = 0;b = 0;}Data(int a, int b) :a(a), b(b){cout << "有參構造" << endl;//this‐>a = a;//this‐>b = b;}void showData(void){cout << "a = " << a << ", b= " << b << endl;}~Data(){cout << "析構函數函數" << endl;}//成員函數 重載前置++ ++ob1 (先加 后使用)//編譯器 默認識別 operator++(a) //但是a可以用this代替 從而化簡 operator++()Data & operator++()//++ob1{ //先加a++;//this‐>a = this‐>a +1b++;//this‐>b = this‐>b +1//后使用return *this;}//成員函數 重載后置++ ob1++ (先使用 后加)//編譯器 默認識別 operator++(a,int) //但是a可以用this代替 從而化簡 operator ++(int)Data & operator++(int)//ob1++{//先使用(備份加之前的值)static Data old = *this;//后加a++;b++;//返回備份值return old;}//重載前置‐‐ ‐‐ob3//編譯器 默認識別 operator++(a) //但是a可以用this代替 從而化簡 operator‐‐()Data & operator--(){//先減a--;b--;//后使用(返回)return *this;}//重載后‐‐ ob4‐‐//編譯器 默認識別 operator++(a,int) //但是a可以用this代替 從而化簡 operator++(int)Data & operator--(int){//先使用static Data old = *this;//再減a--;b--;return old;}};//普通全局函數 作為類的友元 重載<<運算符ostream & operator<<(ostream & out, Data & ob){out << "a = " << ob.a << ", b = " << ob.b;return out;}void test01(){Data ob1(10, 20);ob1.showData();//重載<<直接輸出自定義對象的值//operator<<(cout,ob1);cout << ob1 << endl;//成員函數 重載 ++運算符cout << ++ob1 << endl;Data ob2(10, 20);cout << ob2++ << endl;cout << ob2 << endl;//成員函數 重載 ‐‐運算符Data ob3(10, 20);cout << "ob3 " << ob3 << endl;cout << --ob3 << endl;Data ob4(10, 20);cout << "ob4 " << ob4 << endl;cout << ob4-- << endl;cout << "ob4 " << ob4 << endl; }int main(int argc, char* argv[]){test01();return 0;}
????????效果如下:?
????????????????感謝你耐心的看到這里?( ′・?・` )比心,如有哪里有錯誤請踢一腳作者o(╥﹏╥)o!??
?????????????????????????????????
?????????????????????????????????????????????????????????????????給個三連再走嘛~??????