C++運算符重載(操作符重載)

運算符重載

  • 1. 運算符重載基礎
    • 1.1 運算符重載語法
    • 1.2 運算符重載細節補充
    • 1.3 更多的運算符重載
  • 2. 重載單目運算符
  • 3. 如何直接輸入輸出對象類型——重載運算符 << 和 >>
    • 3.1 單個對象實現 cou <<
    • 3.2 多個對象實現 cout<<
    • 3.3 右移運算符 輸入 cin >>
    • 3.4 重載括號運算符(仿函數/函數對象)
  • 4. 重載運算符注意事項

1. 運算符重載基礎

C++將運算符重載擴展到自定義的數據類型,它可以讓對象操作更美觀。

例如字符串string用加號(+)拼接、cout用兩個左尖括號(<<)輸出。

有時候我們需要讓對象之間進行運算, C++ 提供的“運算符重載”機制,賦予運算符新的功能,就能解決用+將兩個復數對象相加這樣的問題。

  • 舉個例子,比如說如下代碼:
    類Point
class Point {friend Point add(Point, Point);int m_x;int m_y;
public:Point(int x, int y) :m_x(x), m_y(y) {}void display() {cout << "(" << m_x << ", " << m_y << ")" << endl;}};

函數add()

Point add(Point p1, Point p2) {return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}

然后在主函數里面我們定義兩個對象,讓兩個點相加

int main() {Point p1(10, 20);Point p2(20, 30);Point p3 = add(p1, p2);p3.display();getchar();return 0;
}

輸出:
在這里插入圖片描述
這樣做就顯得很繁瑣,如果可以直接這么寫就好了:

Point p3 = p1 + p2;

也就是直接讓這兩個對象進行相加操作,
但是默認情況下這么寫報錯
所以我們可以利用 運算符重載(操作符重載):可以為運算符增加一些新的功能

1.1 運算符重載語法

返回值 operator運算符(參數列表);

接著剛才的問題,我們利用運算符重載為運算符增加一些新的功能,使得“+”可以允許兩個Point類型進行相加操作。

Point operator+(Point p1, Point p2) {return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}

不要忘記在Point類里面更新友元:

friend Point operator+(Point, Point);

完整代碼:

#include <iostream>
using namespace std;class Point {friend Point operator+(Point, Point);int m_x;int m_y;
public:Point(int x, int y) :m_x(x), m_y(y) {}void display() {cout << "(" << m_x << ", " << m_y << ")" << endl;}};//Point add(Point p1, Point p2) {
//	return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
//}
Point operator+(Point p1, Point p2) {return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}int main() {Point p1(10, 20);Point p2(20, 30);Point p3 = p1 + p2;p3.display();getchar();return 0;
}

輸出:
在這里插入圖片描述

  • 本質上是調用了 operator+() 函數,并且返回了 Point 類型值
// 這兩行代碼等價
Point p3 = operator+(p1, p2);Point p3 = p1 + p2;
  • 利用運算符重載為運算符后,三個數相加也可以
    例:
int main() {Point p1(10, 20);Point p2(20, 30);Point p3(30, 40);Point p4 = p1 + p2 + p3;p4.display();getchar();return 0;
}

輸出:
在這里插入圖片描述
此時三個對象相加也可以了,所以還是比直接調用 add()函數 要方便的多

原理是這樣的:

// 調用了兩次operaator+
Point p4 = operator+(operator+(p1, p2), p3) ;

1.2 運算符重載細節補充

之前在 C++ 對象型參數和返回值 的帖子筆記中提到,最好不要在函數參數使用對象型類型,不然會產生中間變量。

Point operator+(Point p1, Point p2) {return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}

修改成 引用(減少中間對象的產生) :

Point operator+(const Point &p1, const Point &p2) {return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}

前面用 const 修飾的原因是可以使加入進來的參數接收對象更廣,既可以接受const對象,也可以接受非const對象。

記得更細友元:

	friend Point operator+(const Point &, const Point &);
  • 有沒有發現這種寫法和拷貝構造函數的格式很類似呢?

拷貝構造函數格式: 類名(const 類名& 對象名){…}

// 拷貝構造函數Point(const Point &point) {m_x = point.m_x;m_y = point.m_y;}

我的理解是也是由于 const 引用既可以接受const參數也可以接受非const參數的原因,它的接受范圍更大

  • 另外,運算符重載也可以直接寫在類里面,這樣就可以直接訪問類里面的成員,我們就省下了去寫友元這一步
  • p.s: const 用來修飾成員函數,如果是在類外,全局函數就不要用const修飾了
#include <iostream>
using namespace std;class Point {friend Point operator+(Point, Point);int m_x;int m_y;
public:Point(int x, int y) :m_x(x), m_y(y) {}void display() {cout << "(" << m_x << ", " << m_y << ")" << endl;}// 運算重載符const Point operator+(const Point &point){return Point(this->m_x + point.m_x, this->m_y + point.m_y);  // this 指針可以省略}};

變成成員函數以后,則需要用對象去調用

p1.operator+(p2);
//等價于
p1 + p2;

那么成員函數中只接收一個參數就可以了

// 運算重載符Point operator+(const Point &point){return Point(this->m_x + point.m_x, this->m_y + point.m_y);  // this 指針可以省略}

還可以再完善以下,左邊的這個const是防止返回值被賦值

右邊的const能保證我們的返回值可以再次調用operator+()函數

// 運算重載符const Point operator+(const Point &point)const{return Point(this->m_x + point.m_x, this->m_y + point.m_y);  // this 指針可以省略}
  • 結論:全局函數和成員函數都支持運算符重載

1.3 更多的運算符重載

除了 “ + ”,還有其他的運算符重載,如 “ - ”(減法運算)

	const Point operator-(const Point &point)const{return Point(m_x - point.m_x, m_y - point.m_y);}

" += "

	Point &operator+=(const Point &point) {m_x += point.m_x;m_y += point.m_y;return *this;	// 取出this指針所指向的東西}

" == "

	bool operator==(const Point &point) const {// 1\0if ((m_x == point.m_x) && (m_y == point.m_y)) {return 1;} else {return 0;}// 或者以下寫法// return (m_x == point.m_x) && (m_y == point.m_y);

“ != ”

	bool operator!=(const Point &point) const {return (m_x != point.m_x) || (m_y != point.m_y);}

" - " (負號)

	const Point operator-() const {return Point(-m_x, -m_y);}

2. 重載單目運算符

可重載的一元運算符:

1)++ 自增 2)-- 自減 3)! 邏輯非 4)& 取地址
5)~ 二進制反碼 6)* 解引用 7)+ 一元加 8) - 一元求反

一元運算符通常出現在它們所操作的對象的左邊。

但是,自增運算符++和自減運算符–有前置和后置之分。

C++ 規定,重載++或–時,如果重載函數有一個int形參,編譯器處理后置表達式時將調用這個重載函數。

  • 區別:1.只需要在參數后面加個 int 就是后置++
// 前置++Point &operator++() {m_x++;m_y++;return *this;}
// 后置++const Point operator++(int) { // 返回const是由于 后置++ 是不能被賦值的(運算符后置++本身的特性)Point old(m_x, m_y);m_x++;m_y++;return old; // 返回的是臨時的變量,因為前置++是先賦值再運算,也就是最后在進行++操作}
  • 2.前置++可以被賦值,后置++不可以
int main() {int a = 10;(++a) = 20; // ++放在前面可以賦值(a++) = 20; // 會報錯,因為相當于先賦值,a再自己+1
}
  • 所以在寫后置++的重載的時候,我們一個是要考慮它本身的不能被賦值的特性(前面用const修飾),一個是返回值應當返回+1之前的值
// 后置++const Point operator++(int) { // 返回const是由于 后置++ 是不能被賦值的(運算符后置++本身的特性)Point old(m_x, m_y);m_x++;m_y++;return old; // 返回的是臨時的變量,因為前置++是先賦值再運算,也就是最后在進行++操作}

3. 如何直接輸入輸出對象類型——重載運算符 << 和 >>

3.1 單個對象實現 cou <<

  • 我們能否能像輸出其他類型一樣,直接將對象進行 cout 呢?
    可以通過對左移運算符進行重載
int main() {Point p1(10, 20);cout << p1 << endl; getchar();return 0;
}

這種情況重載就不能寫在類里了,因為左移運算符左邊是cout,而想要調用類里的成員函數首先要是對象才行,而cout顯然不是對象,所以要寫在類的外面

// output stream -> ostream 輸出流
void operator<<(ostream& cout, const Point& point) {cout << "(" << point.m_x << ", " << point.m_y << ")";
}

(ostream 是 cout 所在的類)

注意不要忘記在類里面放友元,不然無法訪問m_x,m_y成員變量

friend void operator<<(ostream &, const Point &);

3.2 多個對象實現 cout<<

  • 如果想實現多個數據的cout:
cout << p1 << p2 << endl;

其實類似如下過程:

cout << p1 << p2 << endl;
// 等價于
operator << (cout, p1) << p2 ;

其實就是得到一次返回值以后,再用這個返回值調用一次左移運算符,所以我們可以更新一下:

// output stream -> ostream 輸出流
ostream& operator<<(ostream& cout, const Point& point) {cout << "(" << point.m_x << ", " << point.m_y << ")";return cout; // 返回cout本身,然后就可以繼續打印
}

更新友元:

friend ostream& operator<<(ostream&, const Point&);

可以用以下代碼實驗

int main() {Point p1(10, 20);Point p2(20, 30);cout << p1 << p2 << endl; getchar();return 0;
}

輸出:可以正常打印對象了

在這里插入圖片描述

3.3 右移運算符 輸入 cin >>

  • 如果我們想從鍵盤輸入一些東西給到對象,該怎么做?
Point p1(10,20);
cin >> p1;

先在類里面更新友元:

friend istream& operator>>(istream&, Point&);

然后和cout類似,istream是cin所在的類,返回一個cin

// input stream -> istream
istream &operator>>(istream &cin, Point &point) {cin >> point.m_x;cin >> point.m_y;return cin;
}

最后可以通過鍵盤輸入查看對象中的值是否被修改了,鍵盤輸入:40 50 60 70

int main() {Point p1(10, 20);Point p2(20, 30);cin >> p1 >> p2;cout << p1 << p2 << endl; getchar();return 0;
}

輸出:
在這里插入圖片描述
對象里的成員變量的值已經更改為鍵盤輸入的值了

3.4 重載括號運算符(仿函數/函數對象)

括號運算符()也可以重載,對象名可以當成函數來使用(函數對象、仿函數)。

括號運算符重載函數的語法:返回值類型 operator()(參數列表);

注意:

  1. 括號運算符必須以成員函數的形式進行重載。
  2. 括號運算符重載函數具備普通函數全部的特征。
  3. 如果函數對象與全局函數同名,按作用域規則選擇調用的函數。

函數對象的用途:

  1. 表面像函數,部分場景中可以代替函數,在STL中得到廣泛的應用;
  2. 函數對象本質是類,可以用成員變量存放更多的信息;
  3. 函數對象有自己的數據類型;
  4. 可以提供繼承體系。

4. 重載運算符注意事項

  1. 返回自定義數據類型的引用可以讓多個運算符表達式串聯起來。(不要返回局部變量的引用)
  2. 重載函數參數列表中的順序決定了操作數的位置。
  3. 重載函數的參數列表中至少有一個是用戶自定義的類型,防止程序員為內置數據類型重載運算符。
  4. 如果運算符重載既可以是成員函數也可以是全局函數,應該優先考慮成員函數,這樣更符合運算符重載的初衷。
  5. 重載函數不能違背運算符原來的含義和優先級
  6. 不能創建新的運算符。
  7. 以下運算符不可重載:

sizeof sizeof運算符
. 成員運算符
.*??? 成員指針運算符
::??? 作用域解析運算符
?:??? 條件運算符
typeid??? 一個RTTI運算符
const_cast??? 強制類型轉換運算符
dynamic_cast??? 強制類型轉換運算符
reinterpret_cast???強制類型轉換運算符
static_cast??? 強制類型轉換運算符

暫時先寫這么多,這部分的知識點還有很多,后面遇到再回來補充

  1. 以下運算符只能通過成員函數進行重載:

= 賦值運算符
() 函數調用運算符
[] 下標運算符
-> 通過指針訪問類成員的運算符

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

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

相關文章

Excel-VBA報錯01-解決方法

【已刪除的部件:部件/xl/vbaProject.bin。(Visual Basic for Applications(VBA))】 1.問題復現&#xff1a; Win10 &#xff1b;64位 &#xff1b;Office Excel 2016 打開帶有宏的Excel文件&#xff0c;報錯&#xff1a;【已刪除的部件&#xff1a;部件/xl/vbaProject.bin。…

KBU1010-ASEMI新能源專用KBU1010

編輯&#xff1a;ll KBU1010-ASEMI新能源專用KBU1010 型號&#xff1a;KBU1010 品牌&#xff1a;ASEMI 封裝&#xff1a;KBU-4 最大重復峰值反向電壓&#xff1a;1000V 最大正向平均整流電流(Vdss)&#xff1a;10A 功率(Pd)&#xff1a;中小功率 芯片個數&#xff1a;4…

pandas數據清洗和統計實例

步驟&#xff1a; 統計每一個列的標簽個數去除或者填充某一列NaN值遍歷某一列分組統計在DataFrame中插入行在DataFrame中追加行 pandas讀取Json數據或csv數據 以一個json數據為例&#xff0c;只要json每一個object都一致就可以&#xff1a; # 讀取json或csv df_f pd.read_…

抖店選品都怎么選品?什么樣的產品更吸引人,更具有購買力?

大家好&#xff0c;我是電商花花。 抖店選品一直都是我們無貨源商家的核心問題&#xff0c;不管是出單、還是爆單&#xff0c;店鋪想要有銷量的前提下都是選品。 很多人一上來就是就是選品&#xff0c;沒有選品經驗還瞎選品&#xff0c;結果到最后選了一堆出單的產品&#xf…

回聲消除原理

回聲消除原理 回聲消除是一種音頻處理技術&#xff0c;用于消除聲學空間中發生的回聲。其基本原理如下&#xff1a; 1. 遠端信號估計 捕獲遠端揚聲器發出的信號&#xff08;通常通過麥克風&#xff09;。使用自適應濾波器估計遠端信號&#xff0c;即回聲信號。 2. 回聲信號…

用wordpress建外貿獨立站的是主流的外貿建站方式

WordPress因其易用性、靈活性和強大的功能支持&#xff0c;成為了外貿企業首選的網站建設平臺。 從技術和功能角度來看&#xff0c;WordPress提供了豐富的主題和插件&#xff0c;這些都是構建專業外貿網站所必需的。例如&#xff0c;有專門為外貿網站設計的主題和插件&#xf…

【棧】Leetcode 驗證棧序列

題目講解 946. 驗證棧序列 算法講解 在這里就只需要模擬一下這個棧的出棧順序即可&#xff1a;使用一個stack&#xff0c;每次讓pushed里面的元素入棧&#xff0c;如果當前棧頂的元素等于poped容器中的當前元素&#xff0c;因此就需要讓棧頂元素出棧&#xff0c;poped的遍歷…

一篇文章幫你搞定微軟云計算證書Renew

IT證書都有過期的時間&#xff0c;像AWS是3年有效期&#xff0c;谷歌是2年&#xff0c;微軟是1年&#xff0c;那這些證書到期該怎么Renew更新呢&#xff1f; 小李哥最近的微軟AZ-204證書要到期了&#xff0c;到期前半年就會收到Microsoft發來提醒郵件。大家在這半年內任何時間都…

500行代碼實現貪吃蛇(2)

文章目錄 3. 貪吃蛇的具體實現 3. 貪吃蛇的具體實現 首先&#xff0c;我們要讓整個程序適應本地化 int main() {//修改適配本地中文環境setlocale(LC_ALL, "");return 0; }蛇身節點的創建 //蛇身結點的定義 typedef struct SnakeNode {int x; int y;struct SnakeN…

Unity 性能優化之LOD技術(十)

提示&#xff1a;僅供參考&#xff0c;有誤之處&#xff0c;麻煩大佬指出&#xff0c;不勝感激&#xff01; 文章目錄 LOD技術效果一、LOD技術是什么&#xff1f;二、LODGroup組件介紹三、LODGroup組件使用步驟添加組件添加模型 四、Project Settings中與LOD組件相關參數總結 L…

【DevOps】Linux 內核網絡子系統全面指南與性能調優

目錄 一、Linux 內核網絡子系統 1. Netfilter 主要特性 工作流程 2. Traffic Control (TC) 主要特性 工作流程 3. Socket 主要特性 工作流程 二、內核參數優化 1. net.ipv4.tcp_window_scaling 2. net.core.netdev_max_backlog 3. net.ipv4.tcp_rmem 和 net.ipv4…

第33次CSP認證Q1:詞頻統計

&#x1f344;題目描述 在學習了文本處理后&#xff0c;小 P 對英語書中的 &#x1d45b;n 篇文章進行了初步整理。 具體來說&#xff0c;小 P 將所有的英文單詞都轉化為了整數編號。假設這 &#x1d45b;n 篇文章中共出現了 &#x1d45a;m 個不同的單詞&#xff0c;則把它們…

網絡編程套接字 (二)---udosocket

本專欄內容為&#xff1a;Linux學習專欄&#xff0c;分為系統和網絡兩部分。 通過本專欄的深入學習&#xff0c;你可以了解并掌握Linux。 &#x1f493;博主csdn個人主頁&#xff1a;小小unicorn ?專欄分類&#xff1a;網絡 &#x1f69a;代碼倉庫&#xff1a;小小unicorn的代…

C++學習第二十九課:C++ 輸入輸出流詳解:從基礎到高級應用

在 C 中&#xff0c;流&#xff08;stream&#xff09;是一種用于實現輸入輸出操作的抽象概念。流可以看作是字節的流動&#xff0c;這些字節可以從一個地方流向另一個地方&#xff0c;例如從鍵盤輸入到程序中&#xff0c;或者從程序輸出到屏幕。C 提供了一套完整的流庫來處理各…

Qt中正則表達式的用法

一.基本功能介紹&#xff1a; 在Qt中&#xff0c;可以使用QRegularExpression類來處理正則表達式。以下是一些常用的正則表達式用法&#xff1a; 1.創建正則表達式對象&#xff1a; QRegularExpression regex("pattern"); 2.匹配字符串&#xff1a; QString str …

LeetCode 2960.統計已測試設備:看測試了多少次

【LetMeFly】2960.統計已測試設備&#xff1a;看測試了多少次 力扣題目鏈接&#xff1a;https://leetcode.cn/problems/count-tested-devices-after-test-operations/ 給你一個長度為 n 、下標從 0 開始的整數數組 batteryPercentages &#xff0c;表示 n 個設備的電池百分比…

【QEMU系統分析之實例篇(十七)】

系列文章目錄 第十七章 QEMU系統仿真的機器創建分析實例 文章目錄 系列文章目錄第十七章 QEMU系統仿真的機器創建分析實例 前言一、QEMU是什么&#xff1f;二、QEMU系統仿真的機器創建分析實例1.系統仿真的命令行參數2.配置加速器configure_accelerators()do_configure_icount…

藍橋杯13屆JAVA A組 國賽

??????? package 藍橋杯國賽; // 貪心選個數最少的進行擺 // 2:1 ,3:1, 4:1,5 : 3,6:3,7:1 // 選 1&#xff0c;7&#xff0c;4&#xff0c;2&#xff0c;3&#xff0c;5&#xff0c;9 // 然后都選滿10個 public class 火彩棒數字 {public static void main(String[] a…

【CTFHub】HTTP 請求方式 302跳轉 cookie WP

1.請求方式 打開給出的URL進入一個頁面&#xff0c;提示原方法是GET&#xff0c;用CTFHUB方法就能獲得flag 思路&#xff1a;抓包&#xff0c;將GET方法改成CTFHUB方法進行重新發送請求&#xff0c;查看響應情況 1.打開代理服務器 2.打開BurpSuite 刷新頁面獲得攔截 3.發送…

【Excel VBA】深入理解 VBA 中的 CallByName 函數

動態調用方法與屬性&#xff1a;深入理解 VBA 中的 CallByName 函數 昨天在介紹Choose函數在復雜的VBA應用程序開發中&#xff0c;有時我們需要根據運行時的情況來決定調用哪個對象的哪個方法或屬性。這種靈活性可以通過 CallByName 函數實現。在本篇博客中&#xff0c;田辛老…