8、操作符重載

友元

  • 可以通過friend關鍵字,把一個全局函數、另一個類的成員函數或者另一個類整體,聲明為授權類的友元
  • 友元擁有訪問授權類任何非公有成員的特權
  • 友元聲明可以出現在授權類的公有、私有或者保護等任何區域不受訪問控制限定符的約束
  • 友元不是成員,其作用域并不隸屬于授權類,也不擁有授權類類型的this指針。

操作符標記和操作符函數

雙目操作符表達式

L#R

成員函數形式:L.operator#(R)

  • 左操作數是調用對象,右操作數是參數對象

全局函數形式:operator#(L,R)

  • 左操作數是第一個參數,右操作數是第二個參數

單目操作符表達式

#O/O#

  • 成員函數形式:O.operator#()
  • 全局函數形式:operator#(O)

三目操作符表達式: F#S#T

三目操作符無法重載

經典雙目操作符

運算類雙目操作符:+、-、*、/等

  • 左右操作數均可以為非常左值、常左值或右值
  • 表達式的結果為右值
// 運算類雙目操作符函數
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}void getInfo(){cout << "姓名:" << m_name << ", 年齡:" << m_age << endl;}// 成員形式操作符函數
//  Human operator+(const Human& r) const {
//      return Human(this->m_age+r.m_age, (this->m_name+"+"+r.m_name).c_str());
//  }
private:int m_age;string m_name;friend Human operator+(const Human& l,const Human& r); // 友元聲明
};
// 全局形式操作符函數
Human operator+(const Human& l, const Human& r){return Human(l.m_age+r.m_age, (l.m_name+"+"+r.m_name).c_str());
}int main(void){Human a(22,"張飛"), b(20,"趙云");  // 非常左值const Human c(25,"關羽"), d(32,"馬超"); // 常左值Human res = a + b; // ==> a.operator+(b)  或 operator+(a,b)res.getInfo();res = c + d; // ==> c.operator+(d)  或 operator+(c,d)res.getInfo();res = Human(45,"黃忠") + Human(35,"劉備"); // ==> Human(45,"黃忠").operator+(Human(35,"劉備")) 或 //     operator+(Human(45,"黃忠"),Human(35,"劉備"))res.getInfo();return 0;
}

賦值類雙目操作符:=、+=、-=、*=、/=等

  • 右操作數可以為非常左值、常左值或右值,但左操作數必須為非常左值
  • 表達式結果為左操作數本身(而非副本)
// 賦值類雙目操作符函數
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}void getInfo(){cout << "姓名:" << m_name << ", 年齡:" << m_age << endl;}// 成員形式操作符函數Human& operator+=(const Human& r){this->m_age = this->m_age + r.m_age;this->m_name = this->m_name + "+" + r.m_name;return *this;}
private:int m_age;string m_name;friend Human operator+(const Human& l,const Human& r); // 友元聲明
};全局形式操作符函數
//Human& operator+(Human& l, const Human& r){
//       l->m_age = l->m_age + r.m_age;
//       l->m_name = l->m_name + "+" + r.m_name;
//       return *l;
//}int main(void){Human a(22,"張飛"), b(20,"趙云");  // 非常左值const Human c(25,"關羽"), d(32,"馬超"); // 常左值((a+=b)+=c)+=Human(45,"黃忠");a.getInfo();return 0;
}

比較類雙目操作符:>、<、==、<=、>=等

  • 左右操作數為非常左值、常左值或右值
  • 表達式結果為 bool
// 比較類雙目操作符函數
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}void getInfo(){cout << "姓名:" << m_name << ", 年齡:" << m_age << endl;}
//    // 成員形式操作符函數
//    bool operator==(/*const Human* this */ const Human& that)const{
//        return this->m_age==that.m_age && this->m_name==that.m_name;
//    }
//    bool operator!=(/*const Human* this */ const Human& that)const{return this->m_age!=that.m_age || this->m_name!=that.m_name;
//        return !(*this==that);//使用operator==
//    }
private:int m_age;string m_name;friend bool operator==(const Human& l, const Human& r); // 友元聲明friend bool operator!=(const Human& l, const Human& r); // 友元聲明
};
// 全局形式操作符函數
bool operator==(const Human& l, const Human& r){return l.m_age==r.m_age && l.m_name==r.m_name;
}
bool operator!=(const Human& l, const Human& r){
//      return l.m_age!=r.m_age || l.m_name!=r.m_name;return !(l==r);//使用operator==
}int main(void){Human a(22,"張飛"), b(20,"趙云");  // 非常左值const Human c(25,"關羽"), d(32,"馬超"); // 常左值cout << (a == b) << endl; //0 ==> a.operator==(b) 或者 ...cout << (a != b) << endl; //1 ==> a.operator!=(b) 或者 ...cout << (c == d) << endl; //0 ==> c.operator==(d) 或者 ...cout << (c != d) << endl; //1 ==> c.operator!=(d) 或者 ...cout << (Human(45,"黃忠") == Human(35,"劉備")) << endl; //0 ==> Human(45,"黃忠").operator==(Human(35,"劉備")) 或者 ...cout << (Human(45,"黃忠") != Human(35,"劉備")) << endl; //1 ==> Human(45,"黃忠").operator!=(Human(35,"劉備")) 或者 ...return 0;
}

經典單目操作符

運算類單目操作符:-、~、!等

  • 操作數為非常左值、常左值或右值
  • 表達式的結果為右值
// 運算類單目操作符函數
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}void getInfo(){cout << "姓名:" << m_name << ", 年齡:" << m_age << endl;}// 成員形式操作符函數Human operator-(/* const Human* this */)const{return Human(-this->m_age,("-"+this->m_name).c_str());}
private:int m_age;string m_name;
//    friend Human operator-(const Human& l); // 友元聲明
};//Human operator-(const Human& l){
//    return Human(-l.m_age,("-"+l.m_name).c_str());
//}
int main(void){Human a(22,"張飛"), b(20,"趙云");  // 非常左值const Human c(25,"關羽"), d(32,"馬超"); // 常左值Human res = -a; // ==> a.operator-() 或  ...res.getInfo();//姓名:-張飛, 年齡:-22res = -c; // ==> c.operator-() 或  ...res.getInfo();//姓名:-關羽, 年齡:-25res = -Human(45,"黃忠"); // ==> Human(45,"黃忠").operator-() 或 ...res.getInfo();//姓名:-黃忠, 年齡:-45return 0;
}

前自增減類單目操作符: 前++、前–

  • 操作數為非常左值
  • 表達式的結果為操作數本身(而非副本)

后自增減類單目操作符: 后+ +、后–

  • 操作數為非常左值
  • 表達式的結果為右值,且為自增減以前的值
// 自增減類單目操作符函數
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}void getInfo(){cout << "姓名:" << m_name << ", 年齡:" << m_age << endl;}//成員形式操作符函數
//    //   前++   ++a
//    Human& operator++(/* Human* this */){
//        this->m_age+=1;   // 直接加1
//        this->m_name+="a";   // 直接加
//        return *this;
//    }后++  a++
//    Human operator++(/* Human* this */int){
//        Human old = *this;   // 備份原來的值
//        this->m_age+=1;  // 直接加1
//        this->m_name+="a";   // 直接加
//        return old;  // 返回原來的值
//    }
private:int m_age;string m_name;friend  Human& operator++(Human&  l); // 友元聲明friend  Human operator++(Human&  l,int); // 友元聲明
};//   前++   ++aHuman& operator++(Human&  l){l.m_age+=1;   // 直接加1l.m_name+="a";   // 直接加return l;}//    后++  a++Human operator++(Human& l,int){Human old = l;   // 備份原來的值l.m_age+=1;  // 直接加1l.m_name+="a";   // 直接加return old;  // 返回原來的值}int main(void){Human a(22,"張飛"), b(20,"趙云");  // 非常左值const Human c(25,"關羽"), d(32,"馬超"); // 常左值//姓名:張飛a, 年齡:23(++a).getInfo(); // a.operator++() 或 ...//姓名:趙云, 年齡:20(/*|...|*/b++).getInfo(); // b.operator++(0) 或 ...//姓名:趙云a, 年齡:21b.getInfo();return 0;
}

其他操作符

輸出操作符: <<

  • 左操作數為非常左值形式的輸出流(ostream)對象,右操作數為左值或右值
  • 表達式的結果為左操作數本身(而非副本)
  • 左操作數的類型為ostream,若以成員函數形式重載該操作符,就應將其定義為ostream類的成員,該類為標準庫提供,無法添加新的成員,因此只能以全局函數形式重載該操作符

ostream& operator< < (ostream& os, const RIGHT& right) { ...}

// 輸入/輸出流操作符函數
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}
/*  void getInfo(){cout << "姓名:" << m_name << ", 年齡:" << m_age << endl;}*/// 成員形式操作符函數
private:int m_age;string m_name;friend ostream& operator<<(ostream& os, const Human& that);friend istream& operator>>(istream& is, Human& that);
};
// 全局形式操作符函數
ostream& operator<<(ostream& os, const Human& that){os << "姓名:" << that.m_name << ", 年齡:" << that.m_age;return os;
}//istream& operator>>(istream& is, Human& that){
//    is >> that.m_name >> that.m_age;
//    return is;
//}int main(void){Human a(22,"張飛");  // 非常左值const Human b(20,"趙云");  // 常左值cout << a << endl; // cout.operator<<(a) 或 operator<<(cout,a)cout << b << endl; // cout.operator<<(b) 或 operator<<(cout,b)cout << Human(45,"黃忠") << endl; // cout.operator<<(Human(45,"黃忠")) 或 operator<<(cout,Human(45,"黃忠"))//    cin >> a; // cin.operator>>(a) 或 operator>>(cin,a)cout << a << endl;return 0;
}

輸入操作符: >>

  • 左操作數為非常左值形式的輸入流(istream)對象,右操作數為非常左值
  • 表達式的結果為左操作數本身(而非副本)
  • 左操作數的類型為istream,若以成員函數形式重載該操作符,就應將其定義為istream類的成員,該類為標準庫提供,無法添加新的成員,因此只能以全局函數形式重載該操作符

istream& operator>> (istream& is, RIGHT& right) { ...}

// 輸入/輸出流操作符函數
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}
/*  void getInfo(){cout << "姓名:" << m_name << ", 年齡:" << m_age << endl;}*/// 成員形式操作符函數
private:int m_age;string m_name;friend ostream& operator<<(ostream& os, const Human& that);friend istream& operator>>(istream& is, Human& that);
};
// 全局形式操作符函數
ostream& operator<<(ostream& os, const Human& that){os << "姓名:" << that.m_name << ", 年齡:" << that.m_age;return os;
}istream& operator>>(istream& is, Human& that){is >> that.m_name >> that.m_age;return is;
}int main(void){Human a(22,"張飛");  // 非常左值cin >> a; // cin.operator>>(a) 或 operator>>(cin,a)cout << a << endl;return 0;
}

下標操作符:[]

  • 一般用于在容器類型中以下標方式獲取數據元素
  • 非常容器的元素為非常左值,常容器的元素為常左值

類型轉換操作符

若源類型是基本類型,目標類型是類類型,則只能通過類型轉換構造函數實現自定義類型轉換

class 目標類型{目標類型(const 源類型& src){ ... }
}

若源類型是類類型,目標類型是基本類型,則只能通過類型轉換操作符函數 實現自定義類型轉換

class 源類型{operator 目標類型(void) const { ...}
}

若源類型和目標類型都是類類型 (而非基本類型) ,則既可以通過類型轉換構造函數也可以通過類型轉換操作符函數實現自定義類型轉換,但不要兩者同時使用

若源類型和目標類型都是基本類型,則無法實現自定義類型轉換,基本類型間的類型轉換規則完全由編譯器內置

操作符重載的局限

不是所有的操作符都能重載,以下操作符不能重載

  • 作用域限定操作符(::)
  • 直接成員訪問操作符(.)
  • 條件操作符(?:)
  • 字節長度操作符(sizeof)
  • 類型信息操作符(typeid)

無法重載所有操作數均為基本類型的操作符: 如實現 1+1=3

c++的前++和后++

  1. 在C語言中
    前++: 先加1,再使用 ++a
    后++: 先使用,再加1 a++
  2. 在C++語言中,不管是前++還是后++,都是直接加1(內部原理和C語言并不同)
    但是C++希望用戶感覺和C一樣

c++的前++和后++的區別

  • 表達式方式區別:i++是先取變量i,再將變量i值+1;而++i是先將變量i值+1,再取變量i。在循環遍歷容器變量時,這兩種方式的結果都是一樣的,但是,本質的效率上有很大的區別,下面介紹另一種效率區別。
  • 效率:兩種方式iterator遍歷的次數是相同的,但在STL中效率不同,前++返回引用,后++返回一個臨時對象,因為iterator是類模板,使用 it++這種形式要返回一個無用的臨時對象,而it++是函數重載,所以編譯器無法對其進行優化,所以每遍歷一個元素,你就創建并銷毀了一個無用的臨時對象。C++的標準庫,還有符合標準C++的教材,除了特殊需要和對內置類型外,基本都是使用++it來進行元素遍歷的,不管是源代碼還是教材中都是如此。

下面是標準庫源碼:
在這里插入圖片描述

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

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

相關文章

elment-table設置el-table-column的label里面的文字換行居中顯示

效果圖如下&#xff1a; 直接上代碼&#xff1a; <el-table class"ut-mt-2" row-key"company" default-expand-all:data"stateQuery.data" style"width: 100%":tree-props"{ children: departList, hasChildren: hasChildre…

Si24R03—低功耗 SOC 芯片(集成RISC-V內核+2.4GHz無線收發器)

Si24R03是一款高度集成的低功耗SOC芯片&#xff0c;其集成了基于RISC-V核的低功耗MCU和工作在2.4GHz ISM頻段的無線收發器模塊。 MCU模塊具有低功耗、Low Pin Count、寬電壓工作范圍&#xff0c;集成了13/14/15/16位精度的ADC、LVD、UART、SPI、I2C、TIMER、WUP、IWDG、RTC等豐…

PandoraFMS 監控軟件 任意文件上傳漏洞復現

0x01 產品簡介 Pandora FMS 是用于監控計算機網絡的軟件。 Pandora FMS 允許以可視化方式監控來自不同操作系統、服務器、應用程序和硬件系統(例如防火墻、代理、數據庫、Web 服務器或路由器)的多個參數的狀態和性能。 0x02 漏洞概述 PandoraFMS upload_head_image.php 接…

.bat文件設置窗口標題、窗口大小、字體及背景顏色?

設置cmd窗口的標題 1、打開.bat文件編輯 2、輸入命令&#xff1a; title&#xff08;窗口標題&#xff09; 比如&#xff1a;title計算機 3、保存 4、雙擊運行.bat文件 &#xff0c;窗口標題改變成功 改變窗口大小 1、打開.bat文件編輯 2、輸入命令&#xff1a; mode co…

Java中的Stream是什么?

在Java中&#xff0c;Stream是一種用于處理集合&#xff08;Collections&#xff09;元素的抽象序列。它允許你在集合上進行不同類型的操作&#xff0c;比如篩選、映射、過濾和歸約等。Stream API引入了一種更函數式的編程風格&#xff0c;能夠簡化集合處理的過程。 Stream并不…

NLP項目實戰01之電影評論分類

介紹&#xff1a; 歡迎來到本篇文章&#xff01;在這里&#xff0c;我們將探討一個常見而重要的自然語言處理任務——文本分類。具體而言&#xff0c;我們將關注情感分析任務&#xff0c;即通過分析電影評論的情感來判斷評論是正面的、負面的。 展示&#xff1a; 訓練展示如下…

【基于LicheePi-4A的 人臉識別系統軟件設計】

參考:https://www.xrvm.cn/community/post/detail?spm=a2cl5.27438731.0.0.31d40dck0dckmg&id=4253195599836418048 1.前言 原先計劃做基于深度學習的炸藥抓取和智能填裝方法研究,但是后來發現板卡不支持pyrealsense2等多個依賴包。因此改變策略,做一款基于LicheePi…

Android Studio的筆記--三元表達式、布爾運算符、與() 或(||) 非(!)

[TOC](三元表達式、布爾運算符、與(&&) 或(||) 非(!)) 表達式 int x 1; int y 2;x < y 結果 true x > y 結果 false x < y 結果 false x > y 結果 true x y 結果 false x ! y 結果 true 布爾運算符 boolean boolean a true; boolean b false; 與…

【Python】列表乘積的計算時間

概述 使用以下三種模式測量了計算列表乘積所需的時間。 使用 for 語句傳遞list使用math模塊使用numpy 下面是實際運行的代碼。 import timestart time.time() A [1] * 100000000 ans 1 for a in A:ans * a print("list loop:", time.time() - start)import m…

前端面試提問(4)

1、手撕防抖與節流、樹與對象的轉換、遞歸調用&#xff0c;鏈表頭插法 1.1、防抖 防抖函數用于延遲執行某個函數&#xff0c;直到過了一定的間隔時間&#xff08;例如等待用戶停止輸入&#xff09;后再執行。 即后一次點擊事件發生時間距離一次點擊事件至少間隔一定時間。 …

笙默考試管理系統-MyExamTest----codemirror(49)

笙默考試管理系統-MyExamTest----codemirror&#xff08;49&#xff09; 目錄 笙默考試管理系統-MyExamTest----codemirror&#xff08;49&#xff09; 一、 笙默考試管理系統-MyExamTest----codemirror 二、 笙默考試管理系統-MyExamTest----codemirror 三、 笙默考試…

有哪些已經上線的vue商城項目?

前言 下面是一些商城的項目&#xff0c;需要練手的同學可以挑選一些來練&#xff0c;廢話少說&#xff0c;讓我們直接開始正題~~ 1、newbee-mall-vue3-app 是一個基于 Vue 3 和 TypeScript 的電商前端項目&#xff0c;它是 newbee-mall 項目的升級版。該項目包含了商品列表、…

內網環境下 - 安裝linux命令、搭建docker以及安裝鏡像

一 內網環境安裝docker 先在外網環境下載好docker二進制文件docker二進制文件下載&#xff0c;要下載對應硬件平臺的文件&#xff0c;否則不兼容 如下載linux平臺下的文件&#xff0c;直接訪問這里即可linux版本docker二進制文件 這里下載docker-24.0.5.tgz 將下載好的文件…

計算機存儲單位 + 程序編譯過程

C語言的編譯過程 計算機存儲單位 頭文件包含的兩種方式 使用 C/C 程序常用的IDE 常用的C語言編譯器&#xff1a; 在選擇編譯器時&#xff0c;需考慮平臺兼容性、性能優化、調試工具和開發人員的個人偏好等因素。 詳細教程可轉 愛編程的大丙

Java編程中通用的正則表達式(一)

正則表達式&#xff08;Regular Expression&#xff0c;簡稱RegEx&#xff09;&#xff0c;又稱常規表示法、正則表示、正規表示式、規則表達式、常式、表達式等&#xff0c;是計算機科學中的一個概念。正則表達式是用于描述某種特定模式的字符序列&#xff0c;特別是用來匹配、…

持續集成和持續交付

引言 CI/CD 是一種通過在應用開發階段引入自動化來頻繁向客戶交付應用的方法。CI/CD 的核心概念是持續集成、持續交付和持續部署。作為一種面向開發和運維團隊的解決方案&#xff0c;CI/CD 主要針對在集成新代碼時所引發的問題&#xff08;亦稱&#xff1a;“集成地獄”&#…

力扣刷題筆記——反轉鏈表

力扣&#xff08;LeetCode&#xff09;官網 - 全球極客摯愛的技術成長平臺 經典問題反轉鏈表 這里給出四種解法 1.雙指針 這種方法是用一個next指針記錄當前節點的下一個節點&#xff0c;一個pre指針記錄當前節點的前一個節點。 只需要遍歷一遍鏈表就可以完成鏈表的反轉 c…

idea__SpringBoot微服務05——JSR303校驗(新注解)(新的依賴),配置文件優先級,多環境切換

JSR303校驗&#xff0c;配置文件優先級&#xff0c;多環境切換 一、JSR303數據校驗二、配置文件優先級三、多環境切換一、properties多環境切換二、yaml多環境切換————————創作不易&#xff0c;如覺不錯&#xff0c;隨手點贊&#xff0c;關注&#xff0c;收藏(*&#x…

電腦待機怎么設置?讓你的電腦更加節能

在日常使用電腦的過程中&#xff0c;合理設置待機模式是一項省電且環保的好習慣。然而&#xff0c;許多用戶對于如何設置電腦待機感到困擾。那么電腦待機怎么設置呢&#xff1f;本文將深入探討三種常用的電腦待機設置方法&#xff0c;通過詳細的步驟&#xff0c;幫助用戶更好地…

【C語言期末】題目+筆記

文章目錄 題目1.下面哪個不是C語言的基本數據類型&#xff1f;&#xff08; B &#xff09;2.C語言的標識符應以字母或&#xff08; A &#xff09;開頭。3.如果需要在C程序里調用標準函數庫中的printf函數&#xff0c;則應該在程序的開頭包含哪個頭文件&#xff1f;&#xff0…