🔥個人主頁 🔥
😈所屬專欄😈?
每文一詩? 💪🏼
? ? ?年年歲歲花相似,歲歲年年人不同 —— 唐/劉希夷《代悲白頭翁》
? ? ? ? 譯文:年年歲歲繁花依舊,歲歲年年看花之人卻不相同
目錄
C++運算符重載概念
C++運算符重載語法及作用
加減乘除運算符重載
賦值運算符重載
返回值作為引用以實現鏈式賦值
關系運算符重載
大于號運算符重載
相等運算符重載
全部代碼
C++運算符重載概念
????????在 C++ 里,運算符重載屬于多態的一種表現形式,它允許你為自定義的數據類型重新定義運算符的行為。
運算符重載其實就是對已有的運算符賦予新的功能,使它能夠處理自定義類型的對象
C++運算符重載語法及作用
語法:返回類型 operator運算符(參數列表) {}
- 提高代碼可讀性:在處理自定義類型時,使用重載后的運算符能讓代碼更直觀、自然。例如,對于自定義的復數類,你可以重載
+
運算符,讓兩個復數相加的操作就像普通數字相加一樣簡單。 - 實現自定義類型的操作:借助運算符重載,你能為自定義類型實現像內置類型那樣的操作。比如,對于自定義的矩陣類,你可以重載
+
、-
、*
等運算符,實現矩陣的加減乘運算。 - 代碼復用與一致性:運算符重載可以復用已有的運算符,使代碼更具一致性。對于熟悉內置運算符的開發者來說,重載后的運算符也易于理解和使用。
加減乘除運算符重載
- 作類成員函數重載
#include <iostream>class human
{
public:human(){};human(int a ,int b):m_a(a),m_b(b){}//加減乘除運算符重載(成員函數)human operator*(const human& h){human h2;h2.m_a = this->m_a * h.m_a;h2.m_b = this->m_b * h.m_b;return h2;}int geta(){return this->m_a;}int getb(){return this->m_b;}private:int m_a;int m_b;};int main(int argc, char const *argv[])
{human h(10,20);human h1(2,10);//相當于 h.operator*(h1)human h3 = h * h1;std::cout << h3.geta() <<" "<< h3.getb()<<std::endl;return 0;
}
代碼解讀:
- 提供默認無參構造函數和函數初始化列表
human(){};human(int a ,int b):m_a(a),m_b(b){}
- 加減乘除運算符重載(成員函數)這里指的是乘法
human operator*(const human& h){human h2;h2.m_a = this->m_a * h.m_a;h2.m_b = this->m_b * h.m_b;return h2;}
- 這里的參數是指常量引用:目的是不使用值傳遞的方式,防止對數據進行大量的拷貝,常量引用本質使用地址傳遞,地址通常占有4個字節,程序效率更高
- 這里的this指向調用該重載函數的哪個對象。
- 在棧區重新創建一個對象h,并將運算后的成員變量更新到該對象并返回。
human h3 = h * h1;
這個相當于 h.operator*(h1)
std::cout << h3.geta() <<" "<< h3.getb()<<std::endl;
因為成員變量m_a和m_b時私有變量,不能在類外訪問,所以在類內使用函數來訪問。
- 輸出
這樣就實現了類型為human的變量使用運算符來進行運算,20 = 10 *2 ;200 = 20*10
其他加減除法以此類推。
2.作全局函數重載
#include <iostream>class human
{friend human operator*(const human& p2, int val);
public:human(){};human(int a ,int b):m_a(a),m_b(b){}//加減乘除運算符重載(成員函數)human operator*(const human& h){human h2;h2.m_a = this->m_a * h.m_a;h2.m_b = this->m_b * h.m_b;return h2;}int geta(){return this->m_a;}int getb(){return this->m_b;}private:int m_a;int m_b;};
// 加減乘除運算符重載(全局函數)訪問私有成員需要加friend聲明
human operator*(const human& p2, int val)
{human temp;temp.m_a = p2.m_a *val;temp.m_b = p2.m_b * val;return temp;
}int main(int argc, char const *argv[])
{human h(10,20);human h1(2,10);//相當與 operator*(h,90)human h2 = h * 90;//相當于 h.operator*(h1)human h3 = h * h1;std::cout << h2.geta() <<" "<< h2.getb()<<std::endl;std::cout << h3.geta() <<" "<< h3.getb()<<std::endl;return 0;
}
代碼解讀:
- ?加減乘除運算符重載(全局函數)訪問私有成員需要加friend聲明
human operator*(const human& p2, int val) {human temp;temp.m_a = p2.m_a *val;temp.m_b = p2.m_b * val;return temp; }
????????該函數在類外定義,在類外定義的函數不能訪問類內的私有變量,但是可以通過友元函數的方法來讓類外定義的全局函數訪問類內的私有變量。即
friend human operator*(const human& p2, int val);
human h2 = h * 90;
?相當與 operator*(h,90)調用的是全局函數。
輸出
賦值運算符重載
返回值作為引用以實現鏈式賦值
#include <iostream>class human
{public:human(){};human(int a ,int b,int c):m_a(a),m_b(b),m_c(new int(c)){}//賦值運算符重載human& operator=(const human& h){if(this != &h){if(m_c != nullptr){delete m_c;m_c = nullptr;}}m_c = new int(*h.m_c);return *this;}int geta(){return this->m_a;}int getb(){return this->m_b;}int getc(){return *this->m_c;}
private:int m_a;int m_b;int* m_c;};int main(int argc, char const *argv[])
{human h(10,20,12);human h1(2,10,34);human h2(22,10,4);h = h1 = h2;std::cout <<h.getc()<<std::endl;return 0;
}
?代碼解讀:
函數初始化列表來初始化成員變量
human(int a ,int b,int c):m_a(a),m_b(b),m_c(new int(c)){}
賦值運算符重載
human& operator=(const human& h){if(this != &h){if(m_c != nullptr){delete m_c;m_c = nullptr;}}m_c = new int(*h.m_c);return *this;}
????? 首先使用this來判斷調用該函數的對象是否和傳入的對象是同一塊內存,接著在判斷調用該成員函數的對象中的成員變量m_c是否不為空,不為空則釋放內存,再置為空。
兩個對象不是同一塊內存(this != &h)需要delete,再重新開辟內存。
這樣作的目的是用于:如果對一個成員變量是指針的對象,將該指針指向的值進行修改時,需要先釋放調用該重載函數的對象中指針變量,再為空,然后在m_c = new int(*h.m_c);重新開辟一塊內存,內存的值是參數中對象的那個值。
原因:若不釋放這塊內存,在賦值操作完成后,原來的內存就會變成無法訪問的 “孤兒” 內存,程序無法再釋放它,從而造成內存泄漏。執行
delete m_c;
就能正確釋放這塊內存,讓系統可以重新使用它。兩個對象是同一塊內存(this == &h)不需要delete。
- 原因:當兩個對象是統一塊內存時,m_c這個指針變量指向的值是一樣的,如果對其執行
delete m_c,
那么在后面
m_c = new int(*h.m_c);時使用*h.m_c時是非法的,因為這塊內存已經被釋放掉了,不能訪問。為什么要m_c = new int(*h.m_c);
- 原因:編譯器默認提供的是淺拷貝,對于一個含有指針變量的類中,淺拷貝會對這塊內存多次釋放,是不合法的,所以需要執行深拷貝來使得兩個對象中的指針變量指向的值相同,但指針的值不同(地址不同)
- 有關【C++面向對象】封裝(上):探尋構造函數的幽微之境-CSDN博客深拷貝,淺拷貝【C++面向對象】封裝(上):探尋構造函數的幽微之境-CSDN博客
為什么return *this;返回值類型是human& 即引用。
- 原因:this指向調用該成員函數的那個對象,而*this是指的該對象,而返回值是human&引用是為了實現鏈式調用,而返回值是human不能實現鏈式賦值,因為他返回的是該對象的拷貝。
關系運算符重載
大于號運算符重載
#include <iostream>class human
{friend bool operator>(const human& h1,int val);
public:human(){};human(int a ,int b,int c):m_a(a),m_b(b),m_c(new int(c)){}//關系運算符重載bool operator>(const human& h1){if(this->m_a > h1.m_a && this->m_b > h1.m_b)return true;elsereturn false;}int geta(){return this->m_a;}int getb(){return this->m_b;}int getc(){return *this->m_c;}
private:int m_a;int m_b;int* m_c;};//關系運算符重載(全局函數)訪問私有成員需要加friend聲明
bool operator>(const human& h1,int val){if(val< h1.m_a && val < h1.m_b)return true;elsereturn false;
}
int main(int argc, char const *argv[])
{human h(10,20,12);human h1(2,10,34);//相當于 h.operator>(h1)if(h > h1)std::cout<<"h>h1"<<std::endl;elsestd::cout<<"h<h1"<<std::endl;//相當與 operator>(h,12)if(h > 12)std::cout<<"h>12"<<std::endl;elsestd::cout<<"h<12"<<std::endl;return 0;
}
?代碼解讀:
上段代碼分別用成員函數和全局函數的方法來實現對自定義類型的判斷
- 對于
h > h1
相當于 h.operator>(h1)
- 對于
h > 12
相當與 operator>(h,12)
- 輸出
相等運算符重載
#include <iostream>class human
{friend bool operator==(const human& h1,int val);
public:human(){};human(int a ,int b,int c):m_a(a),m_b(b),m_c(new int(c)){}//關系運算符重載bool operator==(const human& h1){if(this->m_a == h1.m_a && this->m_b == h1.m_b)return true;elsereturn false;}int geta(){return this->m_a;}int getb(){return this->m_b;}int getc(){return *this->m_c;}
private:int m_a;int m_b;int* m_c;};//關系運算符重載(全局函數)訪問私有成員需要加friend聲明
bool operator==(const human& h1,int val){if(val == h1.m_a)return true;elsereturn false;
}int main(int argc, char const *argv[])
{human h(10,20,12);human h1(2,10,34);//相當于 h.operator==(h1)if(h == h1)std::cout<<"二者相等"<<std::endl;elsestd::cout<<"二者不等"<<std::endl;//相當與 operator==(h,23)if(h == 23)std::cout<<"二者相等"<<std::endl;elsestd::cout<<"二者不等"<<std::endl;return 0;
}
??代碼解讀:
上段代碼分別用成員函數和全局函數的方法來實現對自定義類型的相等判斷
- 對于
h == h1
相當于相當于 h.operator==(h1)
- 對于
h == 23
相當于 operator==(h,23)
- 輸出
全部代碼
#include <iostream>class human
{friend human operator*(const human& p2, int val);friend bool operator==(const human& h1,int val);friend bool operator>(const human& h1,int val);
public:human(){};human(int a ,int b,int c):m_a(a),m_b(b),m_c(new int(c)){}//加減乘除運算符重載(成員函數)human operator*(const human& h){human h2;h2.m_a = this->m_a * h.m_a;h2.m_b = this->m_b * h.m_b;return h2;}//關系運算符重載bool operator==(const human& h1){if(this->m_a == h1.m_a && this->m_b == h1.m_b)return true;elsereturn false;}//關系運算符重載bool operator>(const human& h1){if(this->m_a > h1.m_a && this->m_b > h1.m_b)return true;elsereturn false;}//賦值運算符重載human& operator=(const human& h){if(this != &h){if(m_c != nullptr){delete m_c;m_c = nullptr;}}m_c = new int(*h.m_c);return *this;}int geta(){return this->m_a;}int getb(){return this->m_b;}int getc(){return *this->m_c;}
private:int m_a;int m_b;int* m_c;};
// 加減乘除運算符重載(全局函數)訪問私有成員需要加friend聲明
human operator*(const human& p2, int val)
{human temp;temp.m_a = p2.m_a *val;temp.m_b = p2.m_b * val;return temp;
}//關系運算符重載(全局函數)訪問私有成員需要加friend聲明
bool operator==(const human& h1,int val){if(val == h1.m_a)return true;elsereturn false;
}
//關系運算符重載(全局函數)訪問私有成員需要加friend聲明
bool operator>(const human& h1,int val){if(val< h1.m_a && val < h1.m_b)return true;elsereturn false;
}
int main(int argc, char const *argv[])
{human h(10,20,12);human h1(2,10,34);//相當與 operator*(h,90)human h2 = h * 90;//相當于 h.operator*(h1)human h3 = h * h1;//相當于 h.operator==(h1)if(h == h1)std::cout<<"二者相等"<<std::endl;elsestd::cout<<"二者不等"<<std::endl;//相當與 operator==(h,23)if(h == 23)std::cout<<"二者相等"<<std::endl;elsestd::cout<<"二者不等"<<std::endl;//相當于 h.operator>(h1)if(h > h1)std::cout<<"h>h1"<<std::endl;elsestd::cout<<"h<h1"<<std::endl;//相當與 operator>(h,12)if(h > 12)std::cout<<"h>12"<<std::endl;elsestd::cout<<"h<12"<<std::endl;std::cout << h2.geta() <<" "<< h2.getb()<<std::endl;std::cout << h3.geta() <<" "<< h3.getb()<<std::endl;h = h1;std::cout <<h.getc()<<std::endl;return 0;
}
?🔥個人主頁 🔥
😈所屬專欄😈?