一文搞懂C++中的運算符重載
引入
對于基本類型的常量或變量進行運算時,我們可以使用 +、-、*、/ 等運算符,但是我們不可以使用運算符來進行對象之間的運算。
eg:對象之間的加法運算
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); }
正如例子中所說:這里我們無法進行對象之間的加法,對于加法操作我們需要使用接口,然后定義add函數(shù)進行加法的操作,這樣也就導(dǎo)致了代碼十分復(fù)雜。
為了使得為了當前程序的可讀性更好,簡單明了。所以我們引入運算符重載這個概念。
利用 C++ 提供的“運算符重載”機制,賦予運算符新的功能,就能解決用+將兩個復(fù)數(shù)對象相加這樣的問題。
一.運算符重載是什么
運算符重載:就是對已有的運算符賦予多重含義,使同一運算符作用于不同類型的數(shù)據(jù)時產(chǎn)生不同的行為。
運算符重載的目的是使得 C++ 中的運算符也能夠用來操作對象。
運算符重載的實質(zhì)是編寫以運算符作為名稱的函數(shù)。
二.運算符重載的格式
返回值類型 operator 運算符(形參表)
{
....
}
這里對于返回值類型 大家可能會產(chǎn)生疑惑:什么是返回值類型,這里對返回值類型進行說明。
返回類型主要包括三類:
- 值返回
- 引用返回
- 指針返回
值返回與引用返回 – 基本數(shù)據(jù)類型
- 值返回:由運算符操作的表達式只能作為右值
- 引用返回: 由運算符所操作的表達式可作為左值
- 指針返回:有指針的相關(guān)操作
void main() { int i =10; int j =20; int k =0; i+j=k;// error 加號的表達式只可以做右值 //i+j有臨時空間來存儲表達式的值,但是沒有確定的,不能把表達式的值放在i或者j空間 //不能作為左值的原因是 沒有相應(yīng)的內(nèi)存空間 i有自己的空間 j有自己的空間 但是i+j沒有 //右邊要賦值給左邊,那么左邊必須要有確定的內(nèi)存空間 k = i+j;//ok ++i = k;//i=30 /* ++i表達式的值 不管在什么時候都是i加過1之后的值,所以不用重新開辟臨時空間存儲表達式的值,用i的空間即可 ++i=k;就是把k的值放在i的內(nèi)存單元 */ i++ = j;//error /* i++的j是i沒有加過的值 但是最后i還是需要+1 所以此時i和i++不是同一個內(nèi)存單元 所以需要重新開辟空間存儲表達式的值,不可以這樣使用 */ (i=j)=40;//=運算符可以作為左值 即可以引用返回 }
這里告訴大家如何快速判斷是值返回還是引用返回:
判斷是左值還是右值
如果對左值右值區(qū)分不是很清楚,可以參考這篇博客:
鏈接: c++左值,右值,將忘值
三.部分運算符重載的實現(xiàn)
3.1 簡單‘ + ’ ‘ - ’ ‘ * ’運算符重載
對于簡單‘ + ’ ‘ - ’ ‘ * ’運算符重載舉例如下:
#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(); }
運算結(jié)果:
3.2 ++,- - 運算符
自增運算符++、自減運算符–都可以被重載,但是它們有前置、后置之分。
以++為例,假設(shè) obj 是一個 CDemo 類的對象,++obj和obj++本應(yīng)該是不一樣的,前者的返回值應(yīng)該是 obj 被修改后的值,而后者的返回值應(yīng)該是 obj 被修改前的值。如果如下重載++運算符:
CDemo & CDemo::operator ++ () { //... return * this; }
不論obj++還是++obj,都等價于obj.operator++()無法體現(xiàn)出差別。
為了解決這個問題,C++ 規(guī)定,在重載++或- -時,允許寫一個增加了無用 int 類型形參的版本,編譯器處理++或–前置的表達式時,調(diào)用參數(shù)個數(shù)正常的重載函數(shù);處理后置表達式時,調(diào)用多出一個參數(shù)的重載函數(shù)。
對于前置運算符:左值 引用返回
對于后置運算符:右值 值返回
舉例如下:
#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); //記錄修改前的對象 n++; return tmp; //返回修改前的對象 } 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++ ) << ","; //等價于 d.operator++(0); cout << d << ","; cout << (++d) << ","; //等價于 d.operator++(); cout << d << endl; cout << (d-- ) << ","; //等價于 operator-(d,0); cout << d << ","; cout << (--d) << ","; //等價于 operator-(d); cout << d << endl; return 0; }
3.3 =運算符
同類對象之間可以通過賦值運算符=互相賦值。如果沒有經(jīng)過重載,=的作用就是把左邊的對象的每個成員變量都變得和右邊的對象相等,即執(zhí)行逐個字節(jié)拷貝的工作,這種拷貝叫作“淺拷貝”。
對于深拷貝淺拷貝可以參考這篇博客:
有的時候,兩個對象相等,從實際應(yīng)用的含義上來講,指的并不應(yīng)該是兩個對象的每個字節(jié)都相同,而是有其他解釋,這時就需要對=進行重載。
如果沒有寫=重載 呢么類會提供默認的=重載
對于=運算符舉例如下:
A& operator=(const A& b) { cout << "=" << endl; m_i = b.m_i; return *this; }
3.4 <<,>>運算符
在 C++ 中,對于左移運算符<<可以和 cout 一起用于輸出,因此也常被稱為“輸出運算符”。
實際上,對于<<來說,他本來并沒有這樣的功能,之所以能和 cout 一起使用,是因為被重載了。
cout 是 ostream 類的對象。ostream 類和 cout 都是在頭文件 中聲明的。ostream 類將<<重載為成員函數(shù),而且重載了多次。為了使cout<<"Star War"能夠成立,ostream 類需要將<<進行如下重載:
ostream & ostream::operator << (const char* s) { //輸出s的代碼 return * this; }
cin 是 istream 類的對象,是在頭文件 中聲明的。istream 類將>>重載為成員函數(shù),因此 cin 才能和>>連用以輸入數(shù)據(jù)。一般也將>>稱為“流提取運算符”或者“輸入運算符”
istream & operator>>( istream & is,Complex & c) { return is; }
四.運算符重載注意事項
1.可以重載成成員和友元兩種形式
對象.operator運算符(第二個運算數(shù))–成員形式
operator運算符(按照順序?qū)戇\算數(shù))–友元形式
2.重載成成員形式,將第一個運算數(shù)省略(當成this)
重載成友元形式,參數(shù)不能省略 。
3.一般建議賦值重載為成員(如果第一個參數(shù)是本類對象,則重載魏本類的成員形式)
[]也建議重載為成員
<< >> 重載成友元,cout<<a.左操作數(shù)是cout的類對象,不可能是本類對象,只能重載為友元。
40運算符重載不可以改變優(yōu)先級,結(jié)合性,操作數(shù)個數(shù)
五.運算符重載的限制
1.不可以臆造新的運算符
2.不可以改變原有運算符的優(yōu)先級,語法等特點。
//不能將求模運算符(%)重載成使用一個操作數(shù): int x; Time shiva; % x;????//無效的求模運算符 % shiva;??//無效的重載操作符
3.運算符重載不可以使用太多
4.重載運算符含義必須清楚,不能有二異性質(zhì)
5.以下運算符不可以重載
6.下列運算符只能通過成員函數(shù)進行重載
- =:賦值運算符
- ():函數(shù)調(diào)用運算符
- []:下標運算符
- ->:通過指針訪問類成員的運算符
六.MyString的簡單實現(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; }
測試函數(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++中的運算符重載的詳細內(nèi)容,更多關(guān)于C++運算符重載的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
深入了解C++優(yōu)先隊列(priority_queue)的使用方法
在計算機科學(xué)中,優(yōu)先隊列是一種抽象數(shù)據(jù)類型,它與隊列相似,但是每個元素都有一個相關(guān)的優(yōu)先級。C++中的優(yōu)先隊列是一個容器適配器(container adapter),它提供了一種在元素之間維護優(yōu)先級的方法。本文帶你深入了解C++優(yōu)先隊列的使用方法,需要的可以參考下2023-05-05C++ 中 <iterator> <functional>&nbs
這篇文章主要介紹了C++ 中 <iterator> <functional> <numeric> 庫好用的函數(shù),本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11