一文搞懂C++中的運(yùn)算符重載
引入
對(duì)于基本類(lèi)型的常量或變量進(jìn)行運(yùn)算時(shí),我們可以使用 +、-、*、/ 等運(yùn)算符,但是我們不可以使用運(yùn)算符來(lái)進(jìn)行對(duì)象之間的運(yùn)算。
eg:對(duì)象之間的加法運(yùn)算
class A
{
public:
A(int i=0,int j=0,int k=0):m_i(i),m_j(j),m_k(k){}
int geti() //接口
{
return m_i;
}
int getj()//接口
{
return m_j;
}
int getk()//接口
{
return m_k;
}
void Add(A &b)
{
int i=m_i+b.m_j;
int j=m_j+b.m_j;
int k=m_k+b.m_k;
cout<<i<<" "<<j<<" "<<k<<" "<<endl;
}
private:
int m_i;
int m_j;
int m_k;
};
void main()
{
A a(6,6,6);
A b(7,7,7);
a.Add(b);
}正如例子中所說(shuō):這里我們無(wú)法進(jìn)行對(duì)象之間的加法,對(duì)于加法操作我們需要使用接口,然后定義add函數(shù)進(jìn)行加法的操作,這樣也就導(dǎo)致了代碼十分復(fù)雜。
為了使得為了當(dāng)前程序的可讀性更好,簡(jiǎn)單明了。所以我們引入運(yùn)算符重載這個(gè)概念。
利用 C++ 提供的“運(yùn)算符重載”機(jī)制,賦予運(yùn)算符新的功能,就能解決用+將兩個(gè)復(fù)數(shù)對(duì)象相加這樣的問(wèn)題。
一.運(yùn)算符重載是什么
運(yùn)算符重載:就是對(duì)已有的運(yùn)算符賦予多重含義,使同一運(yùn)算符作用于不同類(lèi)型的數(shù)據(jù)時(shí)產(chǎn)生不同的行為。
運(yùn)算符重載的目的是使得 C++ 中的運(yùn)算符也能夠用來(lái)操作對(duì)象。
運(yùn)算符重載的實(shí)質(zhì)是編寫(xiě)以運(yùn)算符作為名稱(chēng)的函數(shù)。
二.運(yùn)算符重載的格式
返回值類(lèi)型 operator 運(yùn)算符(形參表)
{
....
}
這里對(duì)于返回值類(lèi)型 大家可能會(huì)產(chǎn)生疑惑:什么是返回值類(lèi)型,這里對(duì)返回值類(lèi)型進(jìn)行說(shuō)明。
返回類(lèi)型主要包括三類(lèi):
- 值返回
- 引用返回
- 指針?lè)祷?/li>
值返回與引用返回 – 基本數(shù)據(jù)類(lèi)型
- 值返回:由運(yùn)算符操作的表達(dá)式只能作為右值
- 引用返回: 由運(yùn)算符所操作的表達(dá)式可作為左值
- 指針?lè)祷兀河兄羔樀南嚓P(guān)操作
void main()
{
int i =10;
int j =20;
int k =0;
i+j=k;// error 加號(hào)的表達(dá)式只可以做右值
//i+j有臨時(shí)空間來(lái)存儲(chǔ)表達(dá)式的值,但是沒(méi)有確定的,不能把表達(dá)式的值放在i或者j空間
//不能作為左值的原因是 沒(méi)有相應(yīng)的內(nèi)存空間 i有自己的空間 j有自己的空間 但是i+j沒(méi)有
//右邊要賦值給左邊,那么左邊必須要有確定的內(nèi)存空間
k = i+j;//ok
++i = k;//i=30
/*
++i表達(dá)式的值 不管在什么時(shí)候都是i加過(guò)1之后的值,所以不用重新開(kāi)辟臨時(shí)空間存儲(chǔ)表達(dá)式的值,用i的空間即可
++i=k;就是把k的值放在i的內(nèi)存單元
*/
i++ = j;//error
/*
i++的j是i沒(méi)有加過(guò)的值 但是最后i還是需要+1 所以此時(shí)i和i++不是同一個(gè)內(nèi)存單元 所以需要重新開(kāi)辟空間存儲(chǔ)表達(dá)式的值,不可以這樣使用
*/
(i=j)=40;//=運(yùn)算符可以作為左值 即可以引用返回
}這里告訴大家如何快速判斷是值返回還是引用返回:
判斷是左值還是右值
如果對(duì)左值右值區(qū)分不是很清楚,可以參考這篇博客:
鏈接: c++左值,右值,將忘值
三.部分運(yùn)算符重載的實(shí)現(xiàn)
3.1 簡(jiǎn)單‘ + ’ ‘ - ’ ‘ * ’運(yùn)算符重載
對(duì)于簡(jiǎn)單‘ + ’ ‘ - ’ ‘ * ’運(yùn)算符重載舉例如下:
#include<stdio.h>
#include<iostream>
using namespace std;
class A
{
public:
A(int i=0):m_i(i){}
A operator+(const A& t)//這里用const是為了本身值不改變
{
cout << "A(+)" << endl;
return m_i + t.m_i;
}
A operator-(const A& t)//這里用const是為了本身值不改變
{
cout << "A(-)" << endl;
return this->m_i-t.m_i;
}
A operator*(const A& t)//這里用const是為了本身值不改變
{
cout << "A(*)" << endl;
return this->m_i*t.m_i;
}
void print()
{
cout << m_i << endl;
}
private:
int m_i;
};
void main()
{
A a(10);
A b(20);
(a + b).print();
(a - b).print();
(a * b).print();
}運(yùn)算結(jié)果:

3.2 ++,- - 運(yùn)算符
自增運(yùn)算符++、自減運(yùn)算符–都可以被重載,但是它們有前置、后置之分。
以++為例,假設(shè) obj 是一個(gè) CDemo 類(lèi)的對(duì)象,++obj和obj++本應(yīng)該是不一樣的,前者的返回值應(yīng)該是 obj 被修改后的值,而后者的返回值應(yīng)該是 obj 被修改前的值。如果如下重載++運(yùn)算符:
CDemo & CDemo::operator ++ ()
{
//...
return * this;
}
不論obj++還是++obj,都等價(jià)于obj.operator++()無(wú)法體現(xiàn)出差別。
為了解決這個(gè)問(wèn)題,C++ 規(guī)定,在重載++或- -時(shí),允許寫(xiě)一個(gè)增加了無(wú)用 int 類(lèi)型形參的版本,編譯器處理++或–前置的表達(dá)式時(shí),調(diào)用參數(shù)個(gè)數(shù)正常的重載函數(shù);處理后置表達(dá)式時(shí),調(diào)用多出一個(gè)參數(shù)的重載函數(shù)。
對(duì)于前置運(yùn)算符:左值 引用返回
對(duì)于后置運(yùn)算符:右值 值返回
舉例如下:
#include <iostream>
using namespace std;
class CDemo {
private:
int n;
public:
CDemo(int i=0):n(i) { }
CDemo & operator++(); //用于前置形式
CDemo operator++( int ); //用于后置形式
operator int ( ) { return n; }
friend CDemo & operator--(CDemo & );
friend CDemo operator--(CDemo & ,int);
};
CDemo & CDemo::operator++()
{//前置 ++
n ++;
return * this;
}
CDemo CDemo::operator++(int k )
{ //后置 ++
CDemo tmp(*this); //記錄修改前的對(duì)象
n++;
return tmp; //返回修改前的對(duì)象
}
CDemo & operator--(CDemo & d)
{//前置--
d.n--;
return d;
}
CDemo operator--(CDemo & d,int)
{//后置--
CDemo tmp(d);
d.n --;
return tmp;
}
int main()
{
CDemo d(5);
cout << (d++ ) << ","; //等價(jià)于 d.operator++(0);
cout << d << ",";
cout << (++d) << ","; //等價(jià)于 d.operator++();
cout << d << endl;
cout << (d-- ) << ","; //等價(jià)于 operator-(d,0);
cout << d << ",";
cout << (--d) << ","; //等價(jià)于 operator-(d);
cout << d << endl;
return 0;
}3.3 =運(yùn)算符
同類(lèi)對(duì)象之間可以通過(guò)賦值運(yùn)算符=互相賦值。如果沒(méi)有經(jīng)過(guò)重載,=的作用就是把左邊的對(duì)象的每個(gè)成員變量都變得和右邊的對(duì)象相等,即執(zhí)行逐個(gè)字節(jié)拷貝的工作,這種拷貝叫作“淺拷貝”。
對(duì)于深拷貝淺拷貝可以參考這篇博客:
有的時(shí)候,兩個(gè)對(duì)象相等,從實(shí)際應(yīng)用的含義上來(lái)講,指的并不應(yīng)該是兩個(gè)對(duì)象的每個(gè)字節(jié)都相同,而是有其他解釋?zhuān)@時(shí)就需要對(duì)=進(jìn)行重載。
如果沒(méi)有寫(xiě)=重載 呢么類(lèi)會(huì)提供默認(rèn)的=重載
對(duì)于=運(yùn)算符舉例如下:
A& operator=(const A& b)
{
cout << "=" << endl;
m_i = b.m_i;
return *this;
}
3.4 <<,>>運(yùn)算符
在 C++ 中,對(duì)于左移運(yùn)算符<<可以和 cout 一起用于輸出,因此也常被稱(chēng)為“輸出運(yùn)算符”。
實(shí)際上,對(duì)于<<來(lái)說(shuō),他本來(lái)并沒(méi)有這樣的功能,之所以能和 cout 一起使用,是因?yàn)楸恢剌d了。
cout 是 ostream 類(lèi)的對(duì)象。ostream 類(lèi)和 cout 都是在頭文件 中聲明的。ostream 類(lèi)將<<重載為成員函數(shù),而且重載了多次。為了使cout<<"Star War"能夠成立,ostream 類(lèi)需要將<<進(jìn)行如下重載:
ostream & ostream::operator << (const char* s)
{
//輸出s的代碼
return * this;
}
cin 是 istream 類(lèi)的對(duì)象,是在頭文件 中聲明的。istream 類(lèi)將>>重載為成員函數(shù),因此 cin 才能和>>連用以輸入數(shù)據(jù)。一般也將>>稱(chēng)為“流提取運(yùn)算符”或者“輸入運(yùn)算符”
istream & operator>>( istream & is,Complex & c)
{
return is;
}
四.運(yùn)算符重載注意事項(xiàng)
1.可以重載成成員和友元兩種形式
對(duì)象.operator運(yùn)算符(第二個(gè)運(yùn)算數(shù))–成員形式
operator運(yùn)算符(按照順序?qū)戇\(yùn)算數(shù))–友元形式
2.重載成成員形式,將第一個(gè)運(yùn)算數(shù)省略(當(dāng)成this)
重載成友元形式,參數(shù)不能省略 。
3.一般建議賦值重載為成員(如果第一個(gè)參數(shù)是本類(lèi)對(duì)象,則重載魏本類(lèi)的成員形式)
[]也建議重載為成員
<< >> 重載成友元,cout<<a.左操作數(shù)是cout的類(lèi)對(duì)象,不可能是本類(lèi)對(duì)象,只能重載為友元。
40運(yùn)算符重載不可以改變優(yōu)先級(jí),結(jié)合性,操作數(shù)個(gè)數(shù)
五.運(yùn)算符重載的限制
1.不可以臆造新的運(yùn)算符
2.不可以改變?cè)羞\(yùn)算符的優(yōu)先級(jí),語(yǔ)法等特點(diǎn)。
//不能將求模運(yùn)算符(%)重載成使用一個(gè)操作數(shù): int x; Time shiva; % x;????//無(wú)效的求模運(yùn)算符 % shiva;??//無(wú)效的重載操作符
3.運(yùn)算符重載不可以使用太多
4.重載運(yùn)算符含義必須清楚,不能有二異性質(zhì)
5.以下運(yùn)算符不可以重載

6.下列運(yùn)算符只能通過(guò)成員函數(shù)進(jìn)行重載
- =:賦值運(yùn)算符
- ():函數(shù)調(diào)用運(yùn)算符
- []:下標(biāo)運(yùn)算符
- ->:通過(guò)指針訪(fǎng)問(wèn)類(lèi)成員的運(yùn)算符
六.MyString的簡(jiǎn)單實(shí)現(xiàn)
MyString.h
#ifndef MYSTRING_H
#define MYSTRING_H
#include<iostream>
using namespace std;
class mystring
{
char * _str;
public:
mystring(const char*str=nullptr);
mystring(const mystring &another);
mystring &operator=(const mystring&another);
mystring operator+(const mystring&another);
char& operator[](const int& i);
bool operator==(const mystring&another);
bool operator<(const mystring &another);
bool operator>(const mystring &another);
friend ostream &operator<<(ostream&out,mystring&str);
int size();
~mystring();
};MyString.cpp
#include "mystring.h"
#include<string.h>
int mystring::size(){
return strlen(this->_str);
}
mystring::mystring (const char* str){
if(str==nullptr)
{
_str=new char[1];
_str[0]='\0';
return;
}
_str=new char[strlen(str)+1];
strcpy(_str,str);
}
mystring::mystring(const mystring &another){
int lenth=strlen(another._str);
_str=new char[lenth+1];
strcpy(_str,another._str);
}
mystring& mystring::operator=( const mystring&another){
if(*this==another)return *this;
else {
delete[] _str;
int lenth=strlen(another._str);
_str=new char[lenth+1];
strcpy(_str,another._str);
return *this;
}
}
mystring mystring:: operator+(const mystring&another){
mystring tmp;
delete[] tmp._str;
int lenth=strlen(_str)+strlen(another._str);
tmp._str=new char[lenth+1];
memset(tmp._str,0,lenth);
strcat(tmp._str,_str);
strcat(tmp._str,another._str);
return tmp;
}
char& mystring:: operator[](const int& i){
return _str[i];
}
bool mystring:: operator==(const mystring&another){
if( strcmp(_str,another._str)==0)
return true;
else return false;
}
bool mystring:: operator<(const mystring &another){
if( strcmp(_str,another._str)<0)
return true;
else return false;
}
bool mystring:: operator>(const mystring &another){
if( strcmp(_str,another._str)>0)
return true;
else return false;
}
ostream & operator<<(ostream&out,mystring&str){
for(int i=0;i<strlen(str._str);++i)
out<<str._str[i];
return out;
}
mystring:: ~mystring(){
delete[]_str;
}測(cè)試函數(shù):
#include<iostream>
#include<mystring.h>
#include<string>
using namespace std;
int main(){
mystring test1("hello");
cout<<test1<<endl;
cout<<test1[0]<<endl;
mystring test2("world");
cout<<test2<<endl;
mystring test3=test1+test2;
cout<<test3<<endl;
if(test1>test2)
cout<<test1<<" > "<<test2<<endl;
else if(test1==test2) cout<<test1<<" = "<<test2<<endl;
else cout<<test1<<" < "<<test2<<endl;
return 1;
}結(jié)果:

以上就是一文搞懂C++中的運(yùn)算符重載的詳細(xì)內(nèi)容,更多關(guān)于C++運(yùn)算符重載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++ 實(shí)現(xiàn)靜態(tài)單鏈表的實(shí)例
這篇文章主要介紹了C++ 實(shí)現(xiàn)靜態(tài)單鏈表的實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-06-06
深入了解C++優(yōu)先隊(duì)列(priority_queue)的使用方法
在計(jì)算機(jī)科學(xué)中,優(yōu)先隊(duì)列是一種抽象數(shù)據(jù)類(lèi)型,它與隊(duì)列相似,但是每個(gè)元素都有一個(gè)相關(guān)的優(yōu)先級(jí)。C++中的優(yōu)先隊(duì)列是一個(gè)容器適配器(container adapter),它提供了一種在元素之間維護(hù)優(yōu)先級(jí)的方法。本文帶你深入了解C++優(yōu)先隊(duì)列的使用方法,需要的可以參考下2023-05-05
C++中虛繼承時(shí)的構(gòu)造函數(shù)示例詳解
在虛繼承中,虛基類(lèi)是由最終的派生類(lèi)初始化的,換句話(huà)說(shuō),最終派生類(lèi)的構(gòu)造函數(shù)必須要調(diào)用虛基類(lèi)的構(gòu)造函數(shù),這跟普通繼承不同,在普通繼承中,派生類(lèi)構(gòu)造函數(shù)中只能調(diào)用直接基類(lèi)的構(gòu)造函數(shù),不能調(diào)用間接基類(lèi)的,所以本文將通過(guò)代碼示例給大家介紹一下C++虛繼承構(gòu)造函數(shù)2023-09-09
C++類(lèi)型轉(zhuǎn)換運(yùn)算符的實(shí)例詳解
這篇文章主要介紹了C++類(lèi)型轉(zhuǎn)換運(yùn)算符的實(shí)例詳解的相關(guān)資料,希望通過(guò)本文大家能夠掌握這部分內(nèi)容,需要的朋友可以參考下2017-09-09
C語(yǔ)言實(shí)現(xiàn)帶頭雙向循環(huán)鏈表
本文主要介紹了C語(yǔ)言實(shí)現(xiàn)帶頭雙向循環(huán)鏈表,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
基于MFC實(shí)現(xiàn)類(lèi)的序列化詳解
序列化是將程序中的對(duì)象以一種二進(jìn)制格式存儲(chǔ)到存儲(chǔ)設(shè)備中(例如文本/數(shù)據(jù)庫(kù)等),以實(shí)現(xiàn)“永生”或隨意“流動(dòng)”。本文將為大家詳細(xì)講講如何基于MFC實(shí)現(xiàn)類(lèi)的序列化,需要的可以參考一下2022-07-07
淺析C語(yǔ)言調(diào)試器GDB和LLDB的使用方法
這篇文章主要介紹了C語(yǔ)言調(diào)試器GDB和LLDB的使用方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12
C++ 中 <iterator> <functional>&nbs
這篇文章主要介紹了C++ 中 <iterator> <functional> <numeric> 庫(kù)好用的函數(shù),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-11-11

