網站首頁 編程語言 正文
引入
對于基本類型的常量或變量進行運算時,我們可以使用 +、-、*、/ 等運算符,但是我們不可以使用運算符來進行對象之間的運算。
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函數進行加法的操作,這樣也就導致了代碼十分復雜。
為了使得為了當前程序的可讀性更好,簡單明了。所以我們引入運算符重載這個概念。
利用 C++ 提供的“運算符重載”機制,賦予運算符新的功能,就能解決用+將兩個復數對象相加這樣的問題。
一.運算符重載是什么
運算符重載:就是對已有的運算符賦予多重含義,使同一運算符作用于不同類型的數據時產生不同的行為。
運算符重載的目的是使得 C++ 中的運算符也能夠用來操作對象。
運算符重載的實質是編寫以運算符作為名稱的函數。
二.運算符重載的格式
返回值類型 ?operator ?運算符(形參表)
{
? ? ....
}
這里對于返回值類型 大家可能會產生疑惑:什么是返回值類型,這里對返回值類型進行說明。
返回類型主要包括三類:
- 值返回
- 引用返回
- 指針返回
值返回與引用返回 – 基本數據類型
- 值返回:由運算符操作的表達式只能作為右值
- 引用返回: 由運算符所操作的表達式可作為左值
- 指針返回:有指針的相關操作
void main()
{
int i =10;
int j =20;
int k =0;
i+j=k;// error 加號的表達式只可以做右值
//i+j有臨時空間來存儲表達式的值,但是沒有確定的,不能把表達式的值放在i或者j空間
//不能作為左值的原因是 沒有相應的內存空間 i有自己的空間 j有自己的空間 但是i+j沒有
//右邊要賦值給左邊,那么左邊必須要有確定的內存空間
k = i+j;//ok
++i = k;//i=30
/*
++i表達式的值 不管在什么時候都是i加過1之后的值,所以不用重新開辟臨時空間存儲表達式的值,用i的空間即可
++i=k;就是把k的值放在i的內存單元
*/
i++ = j;//error
/*
i++的j是i沒有加過的值 但是最后i還是需要+1 所以此時i和i++不是同一個內存單元 所以需要重新開辟空間存儲表達式的值,不可以這樣使用
*/
(i=j)=40;//=運算符可以作為左值 即可以引用返回
}
這里告訴大家如何快速判斷是值返回還是引用返回:
判斷是左值還是右值
如果對左值右值區分不是很清楚,可以參考這篇博客:
鏈接: c++左值,右值,將忘值
三.部分運算符重載的實現
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();
}
運算結果:
3.2 ++,- - 運算符
自增運算符++、自減運算符–都可以被重載,但是它們有前置、后置之分。
以++為例,假設 obj 是一個 CDemo 類的對象,++obj和obj++本應該是不一樣的,前者的返回值應該是 obj 被修改后的值,而后者的返回值應該是 obj 被修改前的值。如果如下重載++運算符:
CDemo & CDemo::operator ++ ()
{
//...
return * this;
}
不論obj++還是++obj,都等價于obj.operator++()無法體現出差別。
為了解決這個問題,C++ 規定,在重載++或- -時,允許寫一個增加了無用 int 類型形參的版本,編譯器處理++或–前置的表達式時,調用參數個數正常的重載函數;處理后置表達式時,調用多出一個參數的重載函數。
對于前置運算符:左值 引用返回
對于后置運算符:右值 值返回
舉例如下:
#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 =運算符
同類對象之間可以通過賦值運算符=互相賦值。如果沒有經過重載,=的作用就是把左邊的對象的每個成員變量都變得和右邊的對象相等,即執行逐個字節拷貝的工作,這種拷貝叫作“淺拷貝”。
對于深拷貝淺拷貝可以參考這篇博客:
鏈接: c++拷貝構造函數
有的時候,兩個對象相等,從實際應用的含義上來講,指的并不應該是兩個對象的每個字節都相同,而是有其他解釋,這時就需要對=進行重載。
如果沒有寫=重載 呢么類會提供默認的=重載
對于=運算符舉例如下:
A& operator=(const A& b)
{
cout << "=" << endl;
m_i = b.m_i;
return *this;
}
3.4 <<,>>運算符
在 C++ 中,對于左移運算符<<可以和 cout 一起用于輸出,因此也常被稱為“輸出運算符”。
實際上,對于<<來說,他本來并沒有這樣的功能,之所以能和 cout 一起使用,是因為被重載了。
cout 是 ostream 類的對象。ostream 類和 cout 都是在頭文件 中聲明的。ostream 類將<<重載為成員函數,而且重載了多次。為了使cout<<"Star War"能夠成立,ostream 類需要將<<進行如下重載:
ostream & ostream::operator << (const char* s)
{
//輸出s的代碼
return * this;
}
cin 是 istream 類的對象,是在頭文件 中聲明的。istream 類將>>重載為成員函數,因此 cin 才能和>>連用以輸入數據。一般也將>>稱為“流提取運算符”或者“輸入運算符”
istream & operator>>( istream & is,Complex & c)
{
return is;
}
四.運算符重載注意事項
1.可以重載成成員和友元兩種形式
對象.operator運算符(第二個運算數)–成員形式
operator運算符(按照順序寫運算數)–友元形式
2.重載成成員形式,將第一個運算數省略(當成this)
重載成友元形式,參數不能省略 。
3.一般建議賦值重載為成員(如果第一個參數是本類對象,則重載魏本類的成員形式)
[]也建議重載為成員
<< >> 重載成友元,cout<<a.左操作數是cout的類對象,不可能是本類對象,只能重載為友元。
40運算符重載不可以改變優先級,結合性,操作數個數
五.運算符重載的限制
1.不可以臆造新的運算符
2.不可以改變原有運算符的優先級,語法等特點。
//不能將求模運算符(%)重載成使用一個操作數:
int x;
Time shiva;
% x;????//無效的求模運算符
% shiva;??//無效的重載操作符
3.運算符重載不可以使用太多
4.重載運算符含義必須清楚,不能有二異性質
5.以下運算符不可以重載
6.下列運算符只能通過成員函數進行重載
- =:賦值運算符
- ():函數調用運算符
- []:下標運算符
- ->:通過指針訪問類成員的運算符
六.MyString的簡單實現
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;
}
測試函數:
#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;
}
結果:
原文鏈接:https://blog.csdn.net/weixin_56935264/article/details/127061754
相關推薦
- 2022-11-14 Go語言官方依賴注入工具Wire的使用教程_Golang
- 2022-04-14 C#可變參數params示例詳解_C#教程
- 2022-04-01 HIVE nvl 空值轉換函數
- 2023-03-11 React中的for循環解讀_React
- 2022-04-12 git error: failed to push some refs to
- 2022-07-12 CSS樣式:行內元素 盒子模型
- 2022-04-24 Android掛斷電話最新實現方法_Android
- 2022-08-25 R語言實現KMeans聚類算法實例教程_R語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支