C++Primer學習(14.1 基本概念)

當運算符作用于類類型的運算對象時,可以通過運算符重載重新定義該運算符的含義。明智地使用運算符重載能令我們的程序更易于編寫和閱讀。舉個例子,因為在Sales_item類中定義了輸入、輸出和加法運算符,所以可以通過下述形式輸出兩個Sales_item的和:

cout << item1 + item2;//輸出兩個Sales item的和

相反的,由于我們的sales_data類還沒有重載這些運算符,因此它的加法代碼顯得比較冗長而不清晰:

print(cout,add(data1,data2));//輸出兩個Sales data的和

14.1 基本概念
重載的運算符是具有特殊名字的函數:它們的名字由關鍵字operator和其后要定義的運算符號共同組成。和其他函數一樣,重載的運算符也包含返回類型、參數列表以及函數體。
重載運算符函數的參數數量與該運算符作用的運算對象數量一樣多。一元運算符有一個參數,二元運算符有兩個。對于二元運算符來說,左側運算對象傳遞給第一個參數,而右側運算對象傳遞給第二個參數。除了重載的函數調用運算符operator()之外,其他重載運算符不能含有默認實參。
如果一個運算符函數是成員函數,則它的第一個(左側)運算對象綁定到隱式的this指針上,因此,成員運算符函數的(顯式)參數數量比運算符的運算對象總數少一個。
Note:當一個重載的運算符是成員函數時,this綁定到左側運算對象。成員運算符函數的(顯式)參數數量比運算對象的數量少一個。
對于一個運算符函數來說,它或者是類的成員,或者至少含有一個類類型的參數:

//錯誤:不能為int 重定義內置的運算符
int operator+(intint);

這一約定意味著當運算符作用于內置類型的運算對象時,我們無法改變該運算符的含義。
我們可以重載大多數(但不是全部)運算符。表14.1指明了哪些運算符可以被重載,哪些不行。我們將在19.1.1節(第726頁)介紹重載new和delete的方法。
我們只能重載已有的運算符,而無權發明新的運算符號。例如,我們不能提供operator**來執行冪操作。
有四個符號(+、-、*、&)既是一元運算符也是二元運算符,所有這些運算符都能被重載,從參數的數量我們可以推斷到底定義的是哪種運算符。
對于一個重載的運算符來說,其優先級和結合律與對應的內置運算符保持一致。不考慮運算對象類型的話,
X == y + Z; 永遠等價于x==(y+z)。
在這里插入圖片描述
直接調用一個重載的運算符函數
通常情況下,我們將運算符作用于類型正確的實參,從而以這種間接方式“調用”重載的運算符函數。然而,我們也能像調用普通函數一樣直接調用運算符函數,先指定函數名字,然后傳入數量正確、類型適當的實參:

//一個非成員運算符函數的等價調用
data1 + data2;//普通的表達式
operator+(datal,data2);//等價的函數調用

這兩次調用是等價的,它們都調用了非成員函數operator+,傳入 data1作為第一個實參、傳入 data2作為第二個實參。
我們像調用其他成員函數一樣顯式地調用成員運算符函數。具體做法是,首先指定運行函數的對象(或指針)的名字,然后使用點運算符(或箭頭運算符)訪問希望調用的函數:

data1+= data2;//基于“調用”的表達式
data1.operator+=(data2);//對成員運算符函數的等價調用

這兩條語句都調用了成員函數 operator+=,將this 綁定到 data1的地址、將 data2作為實參傳入了函數。
某些運算符不應該被重載
回憶之前介紹過的,某些運算符指定了運算對象求值的順序。因為使用重載的運算符本質上是一次函數調用,所以這些關于運算對象求值順序的規則無法應用到重載的運算符上。特別是,邏輯與運算符、邏輯或運算符和逗號運算符的運算對象求值順序規則無法保留下來。除此之外,&&和||運算符的重載版本也無法保留內置運算符的短路求值屬性,兩個運算對象總是會被求值。
因為上述運算符的重載版本無法保留求值順序和/或短路求值屬性,因此不建議重載它們。當代碼使用了這些運算符的重載版本時,用戶可能會突然發現他們一直習慣的求值規則不再適用了。
還有一個原因使得我們一般不重載逗號運算符和取地址運算符:C++語言已經定義了這兩種運算符用于類類型對象時的特殊含義,這一點與大多數運算符都不相同。因為這兩種運算符已經有了內置的含義,所以一般來說它們不應該被重載,否則它們的行為將異于常態,從而導致類的用戶無法適應。
BestPrntices 通常情況下,不應該重載逗號、取地址、邏輯與和邏輯或運算符。
使用與內置類型一致的含義
當你開始設計一個類時,首先應該考慮的是這個類將提供哪些操作。在確定類需要哪些操作之后,才能思考到底應該把每個類操作設成普通函數還是重載的運算符。如果某些操作在邏輯上與運算符相關,則它們適合于定義成重載的運算符:
(1)如果類執行I0操作,則定義移位運算符使其與內置類型的I0保持一致。
(2)如果類的某個操作是檢查相等性,則定義operator==;如果類有了operator==,意味著它通常也應該有operator!=。
(3)如果類包含一個內在的單序比較操作,則定義operator<;如果類有了operator<,則它也應該含有其他關系操作。
(4)重載運算符的返回類型通常情況下應該與其內置版本的返回類型兼容:邏輯運算符和關系運算符應該返回 bool,算術運算符應該返回一個類類型的值,賦值運算符和復合賦值運算符則應該返回左側運算對象的一個引用。
提示:盡量明智地使用運算符重載
每個運算符在用于內置類型時都有比較明確的含義。以二元+運算符為例,它明顯執行的是加法操作。因此,把二元+運算符映射到類類型的一個類似操作上可以極大地簡化記憶。例如對于標準庫類型string來說,我們就會使用+把一個string對象連接到另一個后面,很多編程語言都有類似的用法。
當在內置的運算符和我們自己的操作之間存在邏輯映射關系時,運算符重載的效果最好。此時,使用重載的運算符顯然比另起一個名字更自然也更直觀。不過,過分濫用運算符重載也會使我們的類變得難以理解。
在實際編程過程中,一般沒有特別明顯的濫用運算符重載的情況。例如,一般來說沒有哪個程序員會定義operator+并讓它執行減法操作。然而經常發生的一種情況是,程序員可能會強行扭曲了運算符的“常規”含義使得其適應某種給定的類型,這顯然是我們不希望發生的。因此我們的建議是:只有當操作的含義對于用戶來說清晰明了時才使用運算符。如果用戶對運算符可能有幾種不同的理解,則使用這樣的運算符將產生二義性。
賦值和復合賦值運算符
賦值運算符的行為與復合版本的類似:賦值之后,左側運算對象和右側運算對象的值相等,并且運算符應該返回它左側運算對象的一個引用。重載的賦值運算應該繼承而非違背其內置版本的含義。
如果類含有算術運算符或者位運算符,則最好也提供對應的復合賦值運算符。無須言,+=運算符的行為顯然應該與其內置版本一致,即先執行+,再執行=。
選擇作為成員或者非成員
當我們定義重載的運算符時,必須首先決定是將其聲明為類的成員函數還是聲明為一個普通的非成員函數。在某些時候我們別無選擇,因為有的運算符必須作為成員:另一些情況下,運算符作為普通函數比作為成員更好
下面的準則有助于我們在將運算符定義為成員函數還是普通的非成員函數做出抉擇:
(1)賦值(=)、下標([])、調用(())和成員訪問箭頭(->)運算符必須是成員。
(2)復合賦值運算符一般來說應該是成員,但并非必須,這一點與賦值運算符略有不同。
(3)改變對象狀態的運算符或者與給定類型密切相關的運算符,如遞增、遞減和解引用運算符,通常應該是成員。
(4)具有對稱性的運算符可能轉換任意一端的運算對象,例如算術、相等性、關系和位運算符等,因此它們通常應該是普通的非成員函數。
程序員希望能在含有混合類型的表達式中使用對稱性運算符。例如,我們能求一個int和一個double的和,因為它們中的任意一個都可以是左側運算對象或右側運算對象,所以加法是對稱的。如果我們想提供含有類對象的混合類型表達式,則運算符必須定義成非成員函數
當我們把運算符定義成成員函數時,它的左側運算對象必須是運算符所屬類的一個對象。例如:

string s="world";
string t=s+"!"; //正確:我們能把一個const char*加到一個string 對象中
string u="hi"+s;//如果+是string的成員,則產生錯誤

如果 operator+是 string 類的成員,則上面的第一個加法等價于s.operator+(“!”)。同樣的,“hi”+s等價于"hi".operator+(s)。顯然"hi"的類型是const char*,這是一種內置類型,根本就沒有成員函數。
因為string將+定義成了普通的非成員函數,所以"hi"+s等價于operator+(“hi”,s)。和任何其他函數調用一樣,每個實參都能被轉換成形參類型。唯一的要求是至少有一個運算對象是類類型,并且兩個運算對象都能準確無誤地轉換成string。

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

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

相關文章

計算機視覺準備八股中

一邊記錄一邊看&#xff0c;這段實習跑路之前運行完3DGAN&#xff0c;弄完潤了&#xff0c;現在開始記憶八股 1.CLIP模型的主要創新點&#xff1a; 圖像和文本兩種不同模態數據之間的深度融合、對比學習、自監督學習 2.等效步長是每一步操作步長的乘積 3.卷積層計算輸入輸出…

基于大語言模型的智能音樂創作系統——從推薦到生成

一、引言&#xff1a;當AI成為音樂創作伙伴 2023年&#xff0c;一款由大語言模型&#xff08;LLM&#xff09;生成的鋼琴曲《量子交響曲》在Spotify沖上熱搜&#xff0c;引發音樂界震動。傳統音樂創作需要數年專業訓練&#xff0c;而現代AI技術正在打破這一壁壘。本文提出一種…

Mysql---鎖篇

1&#xff1a;MySQL 有哪些鎖&#xff1f; 全局鎖 flush tables with read lock 整個數據庫就處于只讀狀態了 unlock tables 釋放全局鎖 全局鎖主要應用于做全庫邏輯備份&#xff0c;這樣在備份數據庫期間&#xff0c;不會因為數據或表結構的更新&#xff0c;而出現備份文件的數…

VLAN綜合實驗二

一.實驗拓撲&#xff1a; 二.實驗需求&#xff1a; 1.內網Ip地址使用172.16.0.0/分配 2.sw1和SW2之間互為備份 3.VRRP/STP/VLAN/Eth-trunk均使用 4.所有Pc均通過DHCP獲取IP地址 5.ISP只能配置IP地址 6.所有…

GEO(生成引擎優化)實施策略全解析:從用戶意圖到效果追蹤

——基于行業實證的AI信源占位方法論 ?一、理解用戶查詢&#xff1a;構建AI語料的核心起點 生成式AI的內容推薦邏輯以用戶意圖為核心&#xff0c;?精準捕捉高頻問題是GEO優化的第一步。企業需通過以下方法挖掘用戶真實需求&#xff1a; ?AI對話日志分析&#xff1a; 分析用…

HTML基礎及進階

目錄 一、HTML基礎 1.什么是HTML 2.常用標簽 &#xff08;1&#xff09;標題標簽&#xff1a;h1-h6數字越小文字會越大&#xff0c;這個標簽會占一整行 &#xff08;2&#xff09;加粗標簽&#xff1a; &#xff08;3&#xff09;換行標簽&#xff1a; &#xff08;4&am…

MSTP與鏈路聚合技術

MSTP&#xff08;多生成樹協議&#xff09; 簡介 MSTP&#xff08;多生成樹協議&#xff09;是Spanning Tree Protocol&#xff08;STP&#xff09;的改進版&#xff0c;支持網絡中使用多條生成樹&#xff0c;并根據用戶需求限制生成樹間的路徑。MSTP將多個VLAN映射到一棵生成…

ModuleNotFoundError: No module named ‘ml_logger.logbook‘

問題 (legion) zhouy24RL-DSlab:~/zhouy24Files/legion/LEGION$ python main.py ML_LOGGER_USER is not set. This is required for online usage. Traceback (most recent call last): File “main.py”, line 7, in from mtrl.app.run import run File “/data/zhouy24File…

c# ftp上傳下載 幫助類

工作中FTP的上傳和下載還是很常用的。如下載打標數據,上傳打標結果等。 這個類常用方法都有了:上傳,下載,判斷文件夾是否存在,創建文件夾,獲取當前目錄下文件列表(不包括文件夾) ,獲取當前目錄下文件列表(不包括文件夾) ,獲取FTP文件列表(包括文件夾), 獲取當前目…

PyTorch 分布式訓練(Distributed Data Parallel, DDP)簡介

PyTorch 分布式訓練&#xff08;Distributed Data Parallel, DDP&#xff09; 一、DDP 核心概念 torch.nn.parallel.DistributedDataParallel 1. DDP 是什么&#xff1f; Distributed Data Parallel (DDP) 是 PyTorch 提供的分布式訓練接口&#xff0c;DistributedDataPara…

策略模式_行為型_GOF23

策略模式 策略模式&#xff08;Strategy Pattern&#xff09;是一種行為型設計模式&#xff0c;核心思想是將一組算法封裝成獨立對象&#xff0c;使它們可以相互替換&#xff0c;從而讓算法的變化獨立于使用它的客戶端。這類似于游戲中的技能切換——玩家根據戰況選擇不同技能…

【Python】天氣數據可視化

1. Python進行數據可視化 在數據分析和科學計算領域&#xff0c;Python憑借其強大的庫和簡潔的語法&#xff0c;成為了眾多開發者和科研人員的首選工具。數據可視化作為數據分析的重要環節&#xff0c;能夠幫助我們更直觀地理解數據背后的規律和趨勢。本文將詳細介紹如何使用P…

深度學習4.4筆記

《動手學深度學習》-4.4-筆記 驗證數據集&#xff1a;通常是從訓練集中劃分出來的一部分數據&#xff0c;不要和訓練數據混在一起&#xff0c;評估模型好壞的數據集 測試數據集&#xff1a;只用一次的數據集 k-折交叉驗證&#xff08;k-Fold Cross-Validation&#xff09;是…

vue 兩種路由模式

一、兩種模式比較 在vue.js中&#xff0c;路由模式分為兩種&#xff1a;hash 模式和 history 模式。這兩種模式決定了URL的結構和瀏覽器歷史記錄的管理方式。 1. hash 模式帶 #&#xff0c;#后面的地址變化不會引起頁面的刷新。換句話說&#xff0c;hash模式不會將#后面的地址…

Android生態大變革,谷歌調整開源政策,核心開發不再公開

“開源”這個詞曾經是Android的護城河&#xff0c;如今卻成了谷歌的燙手山芋。最近谷歌宣布調整Android的開源政策&#xff0c;核心開發將全面轉向私有分支。翻譯成人話就是&#xff1a;以后Android的核心更新&#xff0c;不再公開共享了。 這操作不就是開源變節嗎&#xff0c;…

JavaScript中集合常用操作方法詳解

JavaScript中集合常用操作方法詳解 JavaScript中的集合主要包括數組(Array)、集合(Set)和映射(Map)。下面我將詳細介紹這些集合類型的常用操作方法。 數組(Array) 數組是JavaScript中最常用的集合類型&#xff0c;提供了豐富的操作方法。 創建數組 // 字面量創建 const ar…

【HC-05】藍牙串口通信模塊調試與應用(1)

一、HC-05 基礎學習視頻 HC-05藍牙串口通信模塊調試與應用1 二、HC-05學習視頻課件

【學Rust寫CAD】18 定點數2D仿射變換矩陣結構體(MatrixFixedPoint結構別名)

源碼 // matrix/fixed.rs use crate::fixed::Fixed; use super::generic::Matrix;/// 定點數矩陣類型別名 pub type MatrixFixedPoint Matrix<Fixed, Fixed, Fixed, Fixed, Fixed, Fixed>;代碼解析 這段代碼定義了一個定點數矩陣的類型別名 MatrixFixedPoint&#xff…

axios文件下載使用后端傳遞的名稱

java后端通過HttpServletResponse 返回文件流 在Content-Disposition中插入文件名 一定要設置Access-Control-Expose-Headers&#xff0c;代表跨域該Content-Disposition返回Header可讀&#xff0c;如果沒有&#xff0c;前端是取不到Content-Disposition的&#xff0c;可以在統…

HarmonyOS之深入解析如何根據url下載pdf文件并且在本地顯示和預覽

一、文件下載 ① 網絡請求配置 下載在線文件&#xff0c;需要訪問網絡&#xff0c;因此需要在 config.json 中添加網絡權限&#xff1a; {"module": {"requestPermissions": [{"name": "ohos.permission.INTERNET","reason&qu…