C++(運算符重載)

?一.友元

C++中使用關鍵字friend可以在類外訪問所有的成員,包括私有成員(之前提到過封裝的核心思想是隱藏內部實現細節,通過公共接口控制訪問),所以友元可以突破封裝的限制訪問數據,盲目使用會導致程序穩定性降低,所以使用友元必須慎重。

友元分類:

????????友元函數

????????友元類

????????友元成員函數

1.友元函數

全局函數訪問私有成員,可以配合運算符重載使用,友元函數是一種在類內“聲明”,類外定義的非成員函數,但是沒訪問類內所有的成員。友元函數可以做到修改私有成員變量

注意:

(1)友元函數沒有this指針。

(2)友元函數可以在類的私有部分,也可以在類的公有部分。
(3)一個函數可以是多個類的友元函數,只需要在不同的類匯中聲明。

#include <iostream>
#include <string>using namespace std;class Techer{
private:int age = 45;string name = "zhangsna";
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name("lisi"){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout << get_age() << endl;cout << get_name() << endl;}int print_age(){return 18;}friend void print_real_age(Techer &t);                //類內聲明友元函數
};void print_real_age(Techer &t){                            //類外定義友元函數cout << "真實年齡:" << t.age << endl;cout << "虛假年齡:" << t.print_age() << endl;t.age = 30;cout << "修改年齡:" << t.age << endl;
}int main (){Techer t1(34,"zhangsan");cout << t1.print_age() << endl;print_real_age(t1);return 0;
}

2.友元類

當B是A的友元類時,類B就可以訪問類A的所有成員,

需要注意的是:

? ? ? ? (1)友元類不具備交換性:A聲明B為友元 → B可訪問A的私有成員,但A不能訪問B的私有成員。

????????(2)友元類不具備傳遞性:A是B的友元,B是C的友元 →?A不是C的友元。

????????(3)友元類不具備繼承性:基類友元不會繼承給派生類。

#include <iostream>
#include <string>using namespace std;class Techer{
private:int age = 45;string name = "zhangsna";
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name("lisi"){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout << get_age() << endl;cout << get_name() << endl;}int print_age(){return 18;}friend class student;
};class Student{
public:void get_name(Techer &t){cout << t.get_name() << endl;}
};int main (){Techer t1(34,"zhangsan");Student s1;s1.get_name(t1);return 0;
}

?友元成員函數

#include <iostream>
#include <string>using namespace std;class Techer; //聲明類class Student{
public:void print_name(Techer &t);
};class Techer{
private:int age = 45;string name = "zhangsna";
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name("lisi"){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout << get_age() << endl;cout << get_name() << endl;}int print_age(){return 18;}friend void Student::print_name(Techer &t);           //1.友元聲明
};//4.實現友元函數
void Student::print_name(Techer &t){cout << t.get_name() <<endl;
}int main (){Techer t1(34,"zhangsan");Student s1;s1.print_name(t1);return 0;
}

二.函數運算符重載

C++中函數是可以重載的運算符也是一種特殊的函數,也可以重載,這樣一來,本來只能基本數據類型能做的加減乘除也可以讓對象直接加減乘除。

函數的三要素是:函數名,參數和返回值。

下面就是C++中運算符+含義,所以我們對+函數進行重載,就可以實現對象之間相加。

可以被重載的運算符:(了解)
????????算術運算符: +、-、*、人、%、++、--
????????位操作運算符:&、|、~、^(位異或)、<<(左移)、>>(右移)
????????邏輯運算符:!、&&、
????????比較運算符:<、>、>=、《=、==、!=
????????賦值運算符:=、+=、-=、*=、/=、%=、&=、 I=、^=、《<=、>>=
????????其他運算符:范、0、->、、new、delete、new[、delete[
不被重載的運算符:
????????成員運算符""、指針運算符“*”、三目運算符"?:“、sizeof、作用域""

1.使用友元函數運算符重載

函數名:+

參數:const Integer &i1和const Integer &i2

返回值:Inteder

    friend Integer operator +(const Integer &i1,const Integer &i2);
#include <iostream>
#include <string>using namespace std;class Integer{
private:int value;
public:Integer(int value):value(value){}int get_value()const{return value;}void set_value(int a){value = a;}friend Integer operator +(const Integer &i1,const Integer &i2);friend Integer operator ++(Integer &i);friend Integer operator ++(Integer &i,int);
};Integer operator +(const Integer &i1,const Integer &i2){return i1.value + i2.value;                //返回兩個int類型,這個時候編譯器會自動幫你創建一個Integer類型的副本,類似于:return Integer(i1.value + i2.value);
}
Integer operator ++(Integer &i){return ++i.value;
}
Integer operator ++(Integer &i,int){return i.value++;
}int main (){Integer i1(3);Integer i2(4);Integer i3 = i1 + i2;cout << i3.get_value() << endl;++i3;cout << (i3++).get_value() << endl;cout << i3.get_value() << endl;return 0;
}

2.使用成員函數運算符重載

簡單三步實現:(投機取巧的方式)

????????(1).把友元函數實現的代碼的friend去掉

????????(2).再把所有傳入的第一個參數去掉,函數內使用this指針替換(不加也可以,編譯器自動識別)

????????(3).在函數名前加上作用域限定符(Integer::)

正常直接寫,就是寫成員函數的步驟。

#include <iostream>
#include <string>using namespace std;class Integer{
private:int value;
public:Integer(int value):value(value){}int get_value()const{return value;}void set_value(int a){value = a;}Integer operator +(const Integer &i);Integer operator ++();Integer operator ++(int);
};Integer Integer::operator +(const Integer &i){return value + i.value;
}
Integer Integer::operator ++(){return ++value;
}
Integer Integer::operator ++(int){return value++;
}int main (){Integer i1(3);Integer i2(4);Integer i3 = i1 + i2;cout << i3.get_value() << endl;++i3;cout << (i3++).get_value() << endl;cout << i3.get_value() << endl;return 0;
}

3.特殊運算符重載

3.1復制運算符重載

如果程序員不手寫賦值運算符重載函數,則編譯器會自動為每個類增加一個賦值運算符重載函數。

在 C++ 中,賦值運算符(operator=必須被重載為類的成員函數,而不能作為友元函數或全局函數。這一設計決策源于 C++ 語言的核心特性:

(1)、根本原因:語言規范要求

C++ 標準(ISO/IEC 14882)明確規定:賦值運算符(=)必須被聲明為類的非靜態成員函數這是語言規范層面的硬性規定,違反此規則將導致編譯錯誤。

(2)、技術原因:this 指針機制
1. 成員函數的隱式 this 指針
  • 成員函數自動獲得隱式?this?指針,指向調用對象

  • 賦值操作需要修改左操作數的狀態,this?提供直接訪問

2. 友元函數缺少 this 指針
  • 友元函數沒有隱式?this?指針

  • 必須顯式聲明兩個參數(左操作數和右操作數)

  • 違反賦值運算符的二元操作符語法形式

#include <iostream>
#include <string>using namespace std;class String{
private:string str;
public:String(string str):str(str){}string get_str(){return str;}void set_str1(string str){this->str = str;}String& operator =(const String& a){        //系統默認自帶的this->str = a.str;return *this;}
};int main (){String s1("hello ");String s2("world");s1 = s2;cout << s1.get_str() << endl;return 0;
}

3.2類型轉換運算符重載

如果我們想把string類型轉換為成員變量,如果正好你的成員變量只有一個string類型的成員變量,這個時候編譯器會自動幫你賦值優化,String s1 = name;就不會報錯,但是你要是想把s1對象賦值給string類型的name,這個時候編譯器就無法識別,需要使用成員函數進行重載。

可以把注釋的部分去掉,錯誤就沒了,注視部分就是類型轉換重載。

#include <iostream>
#include <string>using namespace std;class String{
private:string str;
public:String(string str):str(str){}string get_str(){return str;}void set_str1(string str){this->str = str;}/*operator string(){return str;}*/
};int main (){String s1("hello ");String s2("world");s1 = s2;string name = s1;cout << name << endl;cout << s1.get_str() << endl;return 0;
}

4.注意:

1.重載的運算符只能對C++語言中已有的運算符進行操作,不能創建新的運算符;

2.運算符重載也是函數重載;

3.運算符不能改變運算符的優先級(*的優先級比+大,不能改變)和結合性(a*b就是a*b不能ab*運算),也不能改變操作數和語法結構;

4.運算符重載函數不支持默認參數,即運算符的操作數數量固定(如二元運算符需要兩個操作數)

5.運算符重載函數的操作數中一定包含自定義類型(運算符重載函數的操作數中必須至少有一個是用戶定義類型

三.string字符串常用手冊

C++函數手冊:

通過網盤分享的文件:C++函數手冊 (LibraryFunctions).chm
鏈接: https://pan.baidu.com/s/17gE3aR6VQhQQ10tBZNFfHg 提取碼: 3589

#include <iostream>
#include <string.h>using namespace std;int main()
{string s1 = "ABC";// 隱式調用了下面的,參數為const char*string s2("ABC");string s3 = s2; // 拷貝構造函數cout << s3 << endl; // ABC// 參數1:const char*// 參數2:保留前幾個字符string s4("ABCDE",2);cout << s4 << endl; // ABs1 = "ABCDE";// 參數1:string// 參數2:不保留前幾個字符string s5(s1,2);cout << s5 << endl; // CDE// 參數1:字符數量// 參數2:字符內容string s6(3,'Z');cout << s6 << endl; // ZZZswap(s5,s6);cout << s5 << " " << s6 << endl; // ZZZ CDE// 向后追加字符串cout << s1.append("...").append(s5) << endl;// 向后追加單字符s6.push_back('O');cout << s6 << endl; // CDEO// 參數1:插入的位置// 參數2:插入的內容s6.insert(1,"222");cout << s6 << endl;// 參數1:刪除的起始位置// 參數2:刪除的字符數s6.erase(1,3);cout << s6 << endl;// 參數1:替換的起始位置// 參數2:替換的字符數// 參數3:替換的字符s6.replace(0,3,"xxxxxxx");cout << s6 << endl;s6.clear(); // 清空// 判斷是否為空cout << s6.empty() << endl; // 1char c[20];s6 = "ABCDEFG";// 參數1:拷貝的目標// 參數2:拷貝的字符數// 參數3:拷貝的起始點s6.copy(c,2,3);cout << c << endl;char c2[20];s6 = "ABCDEFG";// c_str返回的char*指向一個內部數組,相對不可控cout << s6.c_str() << endl;// 因此需要拷貝出來strcpy(c2,s6.c_str());cout << c2 << endl;return 0;
}

練完后會不會有個疑問,為什么string有這么多操作,之前說過他不是基本數據類型,因為它就是C++中定義好的類。

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

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

相關文章

XR-RokidAR-UXR3.0-Draggable 腳本解析

using System.Collections.Generic; using Rokid.UXR.Utility; using UnityEngine; using UnityEngine.EventSystems;namespace Rokid.UXR.Interaction {/// <summary>/// Draggable 拖拽組件/// </summary>// [RequireComponent(typeof(RayInteractable))]public …

GitHub 趨勢日報 (2025年06月17日)

&#x1f4ca; 由 TrendForge 系統生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日報中的項目描述已自動翻譯為中文 &#x1f4c8; 今日獲星趨勢圖 今日獲星趨勢圖 1022 anthropic-cookbook 986 awesome-llm-apps 910 fluentui-system-icons 754 r…

NodeJS的中間件是什么

說簡單一點&#xff0c;中間件就是在你的請求和業務邏輯之間做一層攔截。 在 Node.js 中&#xff0c;中間件&#xff08;Middleware&#xff09; 是一種函數&#xff0c;它在 請求&#xff08;Request&#xff09;到達路由處理器之前&#xff0c;或在 響應&#xff08;Respons…

MCAL學習(6)——診斷、DCM

1.診斷概述 汽車診斷就是通過汽車總線&#xff08;CAN LIN Eth&#xff09;來進行診斷會話&#xff0c;大部分通過CAN總線通訊進行請求與響應。 1.診斷分層 DCM內部支持UDS服務和OBD服務&#xff08;排放&#xff0c;動力&#xff09;。 以統一診斷服務UDS為例&#xff0c;應…

kafka-生產者-(day-4)

day-3 BufferPool 產生原因&#xff1a;ByteBuffer的創建和釋放都是比較耗費資源的&#xff0c;為了實現內存的高效利用&#xff0c;產生了他。他會對特定大小的ByteBuffer進行管理 BufferPool的字段 free:是一個ArrayDeque隊列&#xff0c;緩存指定大小的ByteBuffer對象Re…

java 驗證ip是否可達

默認IP的設備已開放ping功能 代碼 public class PingTest {public static void main(String[] args) throws Exception {String ip "192.168.21.101";boolean reachable InetAddress.getByName(ip).isReachable(3000);System.out.println(ip (reachable ? &quo…

LeetCode 2187.完成旅途的最少時間

題目&#xff1a; 給你一個數組 time &#xff0c;其中 time[i] 表示第 i 輛公交車完成 一趟旅途 所需要花費的時間。 每輛公交車可以 連續 完成多趟旅途&#xff0c;也就是說&#xff0c;一輛公交車當前旅途完成后&#xff0c;可以 立馬開始 下一趟旅途。每輛公交車 獨立 運…

永磁同步電機無速度算法--基于正切函數鎖相環的滑模觀測器

最近在學習鎖相環&#xff0c;后續會記錄一下了解到的幾種PLL。 一、原理介紹 傳統鎖相環控制框圖如下所示 在電機正轉時&#xff0c;傳統鎖相環可以實現很好的轉速和轉子位置估計&#xff0c;但是當電機反轉&#xff0c;反電動勢符號發生變化&#xff0c;系統估計轉子位置最…

Vim-vimrc 快捷鍵映射

Vim-vimrc 快捷鍵映射 文章目錄 Vim-vimrc 快捷鍵映射Leader 鍵快捷鍵映射&#xff1a;插入特定字符插入 --插入 ##插入 解釋Leader鍵設置快速插入分隔線 Leader 鍵 我們還將 , 設置為 Leader 鍵&#xff0c;使得其他快捷鍵映射更加簡潔。 let mapleader ","快捷鍵…

SylixOS armv7 任務切換

SylixOS 操作系統下&#xff0c;任務切換可以分為兩種 中斷退出時&#xff0c;執行的任務切換&#xff08;_ScheduleInt&#xff09;內核退出時&#xff0c;執行的任務切換&#xff08;_Schedule&#xff09; 下面分別講講這兩種任務切換 1、中斷退出時任務切換 關于 ARM 架…

Java 自定義異常:如何優雅地處理程序中的“業務病”?

&#x1f525;「炎碼工坊」技術彈藥已裝填&#xff01; 點擊關注 → 解鎖工業級干貨【工具實測|項目避坑|源碼燃燒指南】 一、從一個真實場景開始&#xff1a;銀行轉賬系統的困境 假設你正在開發一個銀行轉賬系統&#xff0c;當用戶嘗試轉賬時可能出現以下問題&#xff1a; 轉…

【JAVA】【Stream流】

1. filter操作 filter()方法用于根據給定的條件過濾列表中的元素&#xff0c;僅保留滿足條件的項。 List<Integer> list Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);List<Integer> res list.stream().filter(a -> a % 2 0).collect(Collectors.toList());for(I…

四、Redis實現限流

簡介&#xff1a; 限流算法在分布式領域是一個經常被提起的話題&#xff0c;當系統的處理能力有限時&#xff0c;如何阻止計劃外的請求繼續對系統施壓。 系統要限定用戶的某個行為在指定的時間里只能允許發生 N 次&#xff0c;如何使用 Redis 的數據結構來實現這個限流的功能&a…

基于Geotools的兩條道路相交并根據交點形成新路線實戰-以OSM數據為例

目錄 前言 一、需求場景及分解 1、需求場景 2、需求應用 二、需求實現 1、加載路網數據 2、獲取道路信息 3、相交點求解 4、生成新道路 5、結果可視化 三、總結 前言 在當今數字化迅速發展的時代&#xff0c;地理空間數據的處理與分析已成為眾多領域不可或缺的關鍵技…

goland有基礎速通(需要其它編程語言基礎)

tip: 無論是變量、方法還是struct的訪問權限控制都是通過命名控制的&#xff0c;命名的首字母是大寫就相當于java中的public&#xff0c;小寫的話就是private&#xff0c;&#xff08;private只有本包可以訪問&#xff09; 1 go的變量聲明 普通變量 特點&#xff1a; 變量類…

量化面試綠皮書:19. 相關系數

文中內容僅限技術學習與代碼實踐參考&#xff0c;市場存在不確定性&#xff0c;技術分析需謹慎驗證&#xff0c;不構成任何投資建議。 19. 相關系數 假設有三個隨機變量x、y和z。 x與y之間的相關系數為0.8&#xff0c;x與z之間的相關系數也是0.8。 Q: 那么y與z之間的最大相關…

新生活的開啟:從 Trae AI 離開后的三個月

很久沒有寫文章了&#xff0c;想借著入職新公司一個月的機會&#xff0c;和大家嘮嘮嗑。 離職 今年2月份我從字節離職了&#xff0c;結束了四年的經歷&#xff0c;當時離開的核心原因是覺得加班時間太長了&#xff0c;平均每天都要工作15&#xff0c;16個小時&#xff0c;周末…

LLM部署之vllm vs deepspeed

部署大語言模型(如 Qwen/LLaMA 等)時,vLLM 與 DeepSpeed 是當前主流的兩種高性能推理引擎。它們各自專注于不同方向,部署流程也有明顯區別。 vLLM 提供極致吞吐、低延遲的推理服務,適用于在線部署;DeepSpeed 更側重訓練與推理混合優化,支持模型并行,適用于推理 + 微調/…

Git(二):基本操作

文章目錄 Git(二)&#xff1a;基本操作添加文件修改文件版本回退撤銷修改情況一&#xff1a;工作區的代碼還沒有 add情況?&#xff1a;已經 add 但沒有 commit情況三&#xff1a;已經 add 并且也 commit 刪除文件 Git(二)&#xff1a;基本操作 添加文件 首先我們先來學習一個…

nginx + ffmpeg 實現 rtsp視頻實時播放和歷史播放

nginx和ffmpeg 的安裝請參考我的另一篇文章 Nginxrtmpffmpeg搭建視頻轉碼服務_nginx-rtmp-module-master-CSDN博客 目錄 1、整體方案設計如圖 2、nginx下目錄創建和配置文件創建 3、創建視頻流生成腳本 4、修改nginx配置 5、管理界面 (video.html) 6、ffmpeg后臺啟動 …