C++學習——C++運算符重載(含義、格式、示例、遵循的規則)

以下內容源于C語言中文網的學習與整理,非原創,如有侵權請告知刪除。

一、運算符重載的含義

所謂重載,就是賦予新的含義。函數重載(Function Overloading)可以讓一個函數名有多種功能,在不同情況下進行不同的操作。運算符重載(Operator Overloading)也是一個道理,同一個運算符可以有不同的功能。

二、運算符重載的格式

運算符重載的格式為:

返回值類型 operator 運算符名稱 (形參表列)
{ //TODO:
}

(1)operator是關鍵字,專門用來定義一個函數(運算符重載函數)。可以將 “operator 運算符名稱”這一部分看做函數名。比如對于上面的代碼,函數名就是operator+

(2)運算符重載函數,除了函數名有特定的格式外,其它地方和普通函數并沒有區別。?

三、簡單的例子說明

例子1:運算符重載函數作為成員函數?

#include<iostream>using namespace std;class complex {
public:complex();complex(double real, double imag);
public:complex operator+ (const complex &A) const;void display() const;
private:double m_real;double m_imag;};complex::complex() :m_real(0.0), m_imag(0.0) {}
complex::complex(double real, double imag) : m_real(real), m_imag(imag) {}complex complex::operator+ (const complex &A) const {complex B;B.m_real = this->m_real + A.m_real;B.m_imag = this->m_imag + A.m_imag;return B;
}void complex::display() const {cout << m_real << "+" << m_imag << "i" << endl;
}int main() {complex c1(4.3, 5.6);complex c2(2.3, 3.7);complex c3;c3 = c1 + c2;c3.display();return 0;
}

上面的例子中,我們在 complex 類中重載了運算符+,該重載只對 complex 對象有效。

當執行“c3 = c1 + c2;”語句時,編譯器檢測到+號左邊(+號具有左結合性,所以先檢測左邊)是一個 complex 對象,就會調用成員函數operator+(),也就是轉換為下面的形式:

c1.operator+(c2)

即 c1 這個對象調用了函數operator+,而 c2 是函數的實參。?

例子2:運算符重載函數作為全局函數

#include <iostream>
using namespace std;class complex{
public:complex();complex(double real, double imag);
public:void display() const;//聲明為友元函數friend complex operator+(const complex &A, const complex &B);
private:double m_real;double m_imag;
};complex operator+(const complex &A, const complex &B);complex::complex(): m_real(0.0), m_imag(0.0){ }
complex::complex(double real, double imag): m_real(real), m_imag(imag){ }
void complex::display() const{cout<<m_real<<" + "<<m_imag<<"i"<<endl;
}//在全局范圍內重載+
complex operator+(const complex &A, const complex &B){complex C;C.m_real = A.m_real + B.m_real;C.m_imag = A.m_imag + B.m_imag;return C;
}int main(){complex c1(4.3, 5.8);complex c2(2.4, 3.7);complex c3;c3 = c1 + c2;c3.display();return 0;
}

因為該運算符重載函數不是 complex 類的成員函數,但是卻用到了 complex 類的 private 成員變量,所以必須在 complex 類中將該函數聲明為友元函數。

當執行“?c3 = c1 + c2;” 語句時,編譯器檢測到+號兩邊都是 complex 對象,就會轉換為類似下面的函數調用:c3 = operator+(c1, c2);

總結:雖然運算符重載所實現的功能完全可以用函數替代,但運算符重載使得程序的書寫更加人性化,易于閱讀。運算符被重載后,原有的功能仍然保留,沒有喪失或改變;而通過運算符重載,擴大了C++已有運算符的功能,使之能用于對象

四、運算符重載時要遵循的規則

1、并不是所有的運算符都可以重載。

2、重載不能改變運算符的優先級和結合性。

3、重載不會改變運算符的用法,原來有幾個操作數、操作數在左邊還是在右邊,這些都不會改變。例如?+號總是出現在兩個操作數之間,重載后也必須如此。

4、運算符重載函數不能有默認的參數,否則就改變了運算符操作數的個數,這顯然是錯誤的。

5、運算符重載函數既可以作為類的成員函數,也可以作為全局函數。

(1)將運算符重載函數作為類的成員函數時,二元運算符的參數只有一個,一元運算符不需要參數。之所以少一個參數,是因為這個參數是隱含的(比如上面的例子1)。

(2)將運算符重載函數作為全局函數時,二元操作符就需要兩個參數,一元操作符需要一個參數,而且其中必須有一個參數是對象(記憶:運算符重載,是在c++引入對象時才有的概念,所以它的一個參數是對象),好讓編譯器區分這是程序員自定義的運算符,防止程序員修改用于內置類型的運算符的性質。

例如,下面這樣是不對的:

int operator + (int a,int b){return (a-b);
}

+號原來是對兩個數相加,現在企圖通過重載使它的作用改為兩個數相減, 如果允許這樣重載的話,那么表達式4+3的結果是 7 還是 1 呢?顯然,這是絕對禁止的。

如果有兩個參數,這兩個參數可以都是對象,也可以一個是對象,一個是C ++內置類型的數據,例如:

complex operator+(int a, complex &c){return complex(a+c.real, c.imag);
}

它的作用是使一個整數和一個復數相加。

(3)另外,將運算符重載函數作為全局函數時,一般都需要在類中將該函數聲明為友元函數。原因很簡單,該函數大部分情況下都需要使用類的 private 成員。

6、箭頭運算符->、下標運算符[ ]、函數調用運算符( )、賦值運算符=只能以成員函數的形式重載。

五、重載數學運算符(示例)

四則運算符(+、-、*、/、+=、-=、*=、/=)和關系運算符(>、<、<=、>=、==、!=)都是數學運算符,它們在實際開發中非常常見,被重載的幾率也很高,并且有著相似的重載格式。本節以復數類 Complex 為例對它們進行重載,重在演示運算符重載的語法以及規范。

復數能夠進行完整的四則運算,但不能進行完整的關系運算:我們只能判斷兩個復數是否相等,但不能比較它們的大小,所以不能對 >、<、<=、>= 進行重載。下面是具體的代碼:

#include <iostream>
#include <cmath>
using namespace std;//復數類
class Complex{
public:  //構造函數Complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ }
public:  //運算符重載//以全局函數的形式重載friend Complex operator+(const Complex &c1, const Complex &c2);friend Complex operator-(const Complex &c1, const Complex &c2);friend Complex operator*(const Complex &c1, const Complex &c2);friend Complex operator/(const Complex &c1, const Complex &c2);friend bool operator==(const Complex &c1, const Complex &c2);friend bool operator!=(const Complex &c1, const Complex &c2);//以成員函數的形式重載Complex & operator+=(const Complex &c);Complex & operator-=(const Complex &c);Complex & operator*=(const Complex &c);Complex & operator/=(const Complex &c);
public:  //成員函數double real() const{ return m_real; }double imag() const{ return m_imag; }
private:double m_real;  //實部double m_imag;  //虛部
};//重載+運算符
Complex operator+(const Complex &c1, const Complex &c2){Complex c;c.m_real = c1.m_real + c2.m_real;c.m_imag = c1.m_imag + c2.m_imag;return c;
}
//重載-運算符
Complex operator-(const Complex &c1, const Complex &c2){Complex c;c.m_real = c1.m_real - c2.m_real;c.m_imag = c1.m_imag - c2.m_imag;return c;
}
//重載*運算符  (a+bi) * (c+di) = (ac-bd) + (bc+ad)i
Complex operator*(const Complex &c1, const Complex &c2){Complex c;c.m_real = c1.m_real * c2.m_real - c1.m_imag * c2.m_imag;c.m_imag = c1.m_imag * c2.m_real + c1.m_real * c2.m_imag;return c;
}
//重載/運算符  (a+bi) / (c+di) = [(ac+bd) / (c2+d2)] + [(bc-ad) / (c2+d2)]i
Complex operator/(const Complex &c1, const Complex &c2){Complex c;c.m_real = (c1.m_real*c2.m_real + c1.m_imag*c2.m_imag) / (pow(c2.m_real, 2) + pow(c2.m_imag, 2));c.m_imag = (c1.m_imag*c2.m_real - c1.m_real*c2.m_imag) / (pow(c2.m_real, 2) + pow(c2.m_imag, 2));return c;
}
//重載==運算符
bool operator==(const Complex &c1, const Complex &c2){if( c1.m_real == c2.m_real && c1.m_imag == c2.m_imag ){return true;}else{return false;}
}
//重載!=運算符
bool operator!=(const Complex &c1, const Complex &c2){if( c1.m_real != c2.m_real || c1.m_imag != c2.m_imag ){return true;}else{return false;}
}//重載+=運算符
Complex & Complex::operator+=(const Complex &c){this->m_real += c.m_real;this->m_imag += c.m_imag;return *this;
}
//重載-=運算符
Complex & Complex::operator-=(const Complex &c){this->m_real -= c.m_real;this->m_imag -= c.m_imag;return *this;
}
//重載*=運算符
Complex & Complex::operator*=(const Complex &c){this->m_real = this->m_real * c.m_real - this->m_imag * c.m_imag;this->m_imag = this->m_imag * c.m_real + this->m_real * c.m_imag;return *this;
}
//重載/=運算符
Complex & Complex::operator/=(const Complex &c){this->m_real = (this->m_real*c.m_real + this->m_imag*c.m_imag) / (pow(c.m_real, 2) + pow(c.m_imag, 2));this->m_imag = (this->m_imag*c.m_real - this->m_real*c.m_imag) / (pow(c.m_real, 2) + pow(c.m_imag, 2));return *this;
}int main(){Complex c1(25, 35);Complex c2(10, 20);Complex c3(1, 2);Complex c4(4, 9);Complex c5(34, 6);Complex c6(80, 90);Complex c7 = c1 + c2;Complex c8 = c1 - c2;Complex c9 = c1 * c2;Complex c10 = c1 / c2;cout<<"c7 = "<<c7.real()<<" + "<<c7.imag()<<"i"<<endl;cout<<"c8 = "<<c8.real()<<" + "<<c8.imag()<<"i"<<endl;cout<<"c9 = "<<c9.real()<<" + "<<c9.imag()<<"i"<<endl;cout<<"c10 = "<<c10.real()<<" + "<<c10.imag()<<"i"<<endl;c3 += c1;c4 -= c2;c5 *= c2;c6 /= c2;cout<<"c3 = "<<c3.real()<<" + "<<c3.imag()<<"i"<<endl;cout<<"c4 = "<<c4.real()<<" + "<<c4.imag()<<"i"<<endl;cout<<"c5 = "<<c5.real()<<" + "<<c5.imag()<<"i"<<endl;cout<<"c6 = "<<c6.real()<<" + "<<c6.imag()<<"i"<<endl;if(c1 == c2){cout<<"c1 == c2"<<endl;}if(c1 != c2){cout<<"c1 != c2"<<endl;}return 0;
}

需要注意的是,我們以全局函數的形式重載了 +、-、*、/、==、!=,以成員函數的形式重載了 +=、-=、*=、/=,而且應該堅持這樣做,不能一股腦都寫作成員函數或者全局函數,具體原因我們將在下節講解。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/160324.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/160324.shtml
英文地址,請注明出處:http://en.pswp.cn/news/160324.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Vue 重寫push和replace方法,解決:Avoided redundant navigation to current location

當我們使用編程式路由導航跳轉路徑時&#xff0c;如果我們兩次攜帶同樣的參數進行跳轉&#xff0c;會進行頁面報錯&#xff1a; 那產生這個問題的原因是什么呢&#xff1f; 我們接收并輸出調用push方法返回的結果&#xff1a; 會發現這是一個Promise對象 我們都知道&#xff…

SAP_ABAP_面試篇_關于Function Module函數的三種處理類型

關于 Function Module 這個技術點&#xff0c;在面試過程中一般會考察以下幾個問題&#xff1a; 1 函數處理類型的更新模式 一般會問到異步和事務&#xff08;邏輯單元 LUW&#xff09;&#xff0c;異步函數的調試方式、SM13監控更新函數的執行過程&#xff08;V1 與 V2 模式…

Epub書籍閱讀工具

Epub書籍閱讀工具 前言WIndows總結Neat ReaderAquile ReaderWPS Android總結Neat Reader掌閱 前言 Epub文件為電子書文件格式&#xff0c;此格式的電子書相比txt書籍&#xff0c;增加了目錄跳轉功能&#xff0c;并可以顯示圖片。本文介紹WIndows和Android端的epub書籍閱讀工具…

SpringBoot中的classpath都包含啥

一句話總結&#xff1a;classpath 等價于 main/java main/resources 第三方jar包的根目錄。下面詳細解釋。 參考&#xff1a;SpringBoot中的classpath

使用Burp發送請求,左下角顯示Unsupported or unrecognized SSL message

這個問題很簡單&#xff0c;那就是源網址使用http協議 而不是https協議

來吧,SpringBoot的自動配置原理都在這里了

&#x1f497;推薦閱讀文章&#x1f497; &#x1f338;JavaSE系列&#x1f338;&#x1f449;1??《JavaSE系列教程》&#x1f33a;MySQL系列&#x1f33a;&#x1f449;2??《MySQL系列教程》&#x1f340;JavaWeb系列&#x1f340;&#x1f449;3??《JavaWeb系列教程》…

Java架構師軟件架構風格

目錄 1 數據流風格1.1 管道過濾器1.2 數據流風格的優點2 調用返回風格2.1 面向對象風格2.2 調用返回風格總結3 獨立構件風格3.1 事件驅動系統風格的主要特點3.2 獨立構件風格總結4 虛擬機風格4.1 虛擬機風格總結5 倉庫風格5.1 倉庫風格總結想學習架構師構建流程請跳轉:Java架構…

8款寶藏級別的云端設計工具推薦

早年&#xff0c;UI設計師選擇的工具有限&#xff0c;功能相對單一&#xff0c;大多數在線原型設計工具都是國外的&#xff0c;語言和網絡都增加了設計工作的負擔。如今&#xff0c;國內外有許多在線原型設計工具&#xff0c;不僅可以在瀏覽器上使用&#xff0c;而且還具有團隊…

SpringBoot集成Swagger2登錄功能和安全認證

本篇文章要實現的功能&#xff1a; 1.集成swagger2.集成swagger登錄功能&#xff0c;訪問 /swagger-ui.html需要先登錄3.集成安全認證&#xff0c;訪問接口時攜帶header 請求接口時攜帶了上一步輸入的header參數和值 1.集成swagger jdk11&#xff0c;SpringBoot 2.7.13 pom…

內網配置git代理

http、https訪問 [http]proxy socks5://192.168.102.xxx:xxxx [https]proxy socks5://192.168.102.xxx:xxx設置ssh訪問 需要修改~/.ssh/config文件&#xff08;&#xff09;, 沒有的話新建一個. 同樣僅為github.com設置代理需要注意~/.ssh/config文件權限為600&#xff0c;…

C語言 子函數調malloc申請內存返回給主函數使用——可行,但要注意

一般情況&#xff0c;子函數中動態申請內存&#xff0c;將地址返回給主函數&#xff0c;理論上應該也是可以的&#xff0c;需要子函數返回動態內存地址&#xff0c;主函數實參是相應的地址變量即可。只不過&#xff0c;主函數實參傳入子函數之前&#xff0c;可能會將指針置空&a…

MatrixOne實戰系列回顧 | 導入導出項目場景實踐

本次分享主要介紹MatrixOne導入導出以及項目場景實踐。將從四個方向為大家演示MatrixOne的功能&#xff0c;分別是數據的導入、導出、對接數據集成工具&#xff0c;以及Java連接實戰。 數據導入會使用三種方式將數據導入至 MatrixOne中。分別是insert語句、load data語句還有s…

學習Opencv(蝴蝶書/C++)——3. OpenCV的數據類型

文章目錄 1. 總覽2. 基礎類型2.0 基礎類型總覽2.1 cv::Vec<>類2.2 cv::Matx<>類2.3 cv::Point類(cv::Point3_< >和cv::Point_< >)2.4 cv::Scalar(cv::Scalar_)類2.5 cv::Size(cv::Size_)類、cv::Rect(cv::Rect_)類和cv::RotatedRect 類2.6 基礎類型…

常見面試題-Redis 主從復制原理以及痛點

Redis 主從復制如何同步數據呢&#xff1f; 參考文章&#xff1a;https://blog.csdn.net/Seky_fei/article/details/106877329 https://zhuanlan.zhihu.com/p/55532249 https://cloud.tencent.com/developer/article/2063597 https://xie.infoq.cn/article/4cffee02a2a12c2…

LongAccumulator

原子操作之LongAccumulator 和LongAdder的區別在于&#xff0c;LongAdder是在Cell里面只能做加減操作&#xff0c;不能乘除&#xff0c;而LongAccumulator就可以定義乘除操作。原理和LongAdder都是一樣的&#xff0c;一個Base和一個Cells數組。 原文跳轉地址

pyqt5的組合式部件制作(四)

對組合式部件的制作又改進了一版&#xff0c;組合式部件的子部件不再需要單獨“提升為”&#xff0c;如果在模板文件的提升部件窗口內選擇了“全局包含”&#xff0c;那么只需要在模板文件和應用文件中直接復制粘貼即可&#xff0c;部件的應用更為簡便。如下圖&#xff1a;按住…

2023秋招上岸必備軟件測試面試題

1、請結合你熟悉的項目&#xff0c;介紹一下你是怎么做測試的&#xff1f; -首先要自己熟悉項目&#xff0c;熟悉項目的需求、項目組織架構、項目研發接口等 -功能 接口 自動化 性能 是怎么處理的&#xff1f; -第一步&#xff1a; 進行需求分析&#xff0c;需求評審&#…

【Delphi】開發IOS 程序,TLabel 中英文字對齊(水平),一行代碼解決顯示對齊問題!

目錄 一、問題現象&#xff1a; 二、解決方案&#xff08;一行代碼解決ios對齊問題&#xff09;&#xff1a; 三、解決后效果&#xff1a; 四、后記&#xff1a; 一、問題現象&#xff1a; 在用 Delphi 開發ios程序時&#xff0c;使用TLabel控件顯示&#xff0c;會出現中英…

WiFi 6的數據在發送端分片和在接收端重組的理解

802.11ax是WiFi 6標準&#xff0c;其引入了一些新的特性和技術來提升無線網絡的性能&#xff0c;其中包括幀聚合和幀分片。以下是它們的詳細處理流程&#xff1a; 1. 幀聚合 幀聚合是一種提高傳輸效率的技術&#xff0c;它允許多個數據幀被聚合到一起&#xff0c;然后作為一個…

layui(2.8.18)生成驗證碼

<!DOCTYPE html> <html> <head><meta charset"utf-8"><title>登入</title><meta name"renderer" content"webkit"><meta http-equiv"X-UA-Compatible" content"IEedge,chrome1&quo…