C++友元:跨墻訪問的三種姿勢

目錄

友元

友元之普通函數形式

友元之成員函數形式

友元類

友元的特點


友元

  • 什么叫友元?

一般來說,類的私有成員只能在類的內部訪問,類之外是不能訪問它們的。但如果將其他類/函數設置為類的友元,那么友元類/函數就可以在前一個類的類定義之外訪問其私有成員了。用friend關鍵字聲明友元

將類比作一個家庭,類的private 成員相當于家庭的秘密,一般的外人當然不允許探聽這些秘密的,只有 friend 才有資格探聽這些秘密。

友元的三種形式:普通函數、成員函數、友元類

友元之普通函數形式

示例:程序中有Point類,需要求取兩個點的距離。按照設想,我們定義一個普通函數distance,接收兩個Point對象作為參數,通過公式計算這兩個點之間的距離。但Point的_ix和 _iy是私有成員,在類外不能通過對象訪問,那么可以將distance函數聲明為Point類的友元函數,之后就可以在distance函數中訪問Point的私有成員了。

class Point{
public:Point(int x, int y): _ix(x), _iy(y){}
?friendfloat distance(const Point & lhs, const Point & rhs);
private:int _ix;int _iy;
};
?
float distance(const Point & lhs, const Point & rhs){return sqrt((lhs._ix - rhs._ix)*(lhs._ix - rhs._ix) +(lhs._iy - rhs._iy)*(lhs._iy - rhs._iy));
}

image-20240312161218053

友元之成員函數形式

假設類A有一個成員函數,該成員函數想去訪問另一個類B類中的私有成員變量。這時候則可以在第二個類B中,聲明第一個類A的那個成員函數為類B的友元函數,這樣第一個類A的某個成員函數就可以訪問第二個類B的私有成員變量了。

我們試驗一下,以另一種方式實現上面的需求,如果distance函數不再是一個普通函數,而是Line類的一個成員函數,也就是說需要在一個類(Line)的成員函數中訪問另一個類(Point)的私有成員,那么又該如何實現呢?

  • 如果將Point類定義在Line類之前,Line類的成員函數要訪問Point類的私有成員,需要在Point類中將Line的這個成員函數設為友元函數——此時編譯器并不認識Line類;

  • 如果將Line類定義在Point類之前,那么distance函數需要接受兩個const Point &作為參數——此時編譯器不認識Point類;

解決方法:

——在Line前面做一個Point類的前向聲明;

——但如果將distance的函數體寫在Line類中,編譯器雖然知道了有一個Point類,但并不知道Point類具體有什么成員,所以此時在函數體中訪問_ix、 _iy都會報錯,編譯器并不認識它們;

思考一下,有什么辦法可以解決這個問題呢?

class Point;//前行聲明
//只有前向聲明,只知道有piont這個類,不知道point是怎么實現的,但不能訪問point的內容,那么我們在line類中
//只做函數的聲明,不做定義
class Line
{//需要前向聲明,使編譯器知道有piont這個類public:float destance(const Point &lhs,const Point &rhs);
};
class Point
{public:Point(int x,int y):_ix(x),_iy(y){}//friend friend float Line::destance(const Point &lhs,const Point &rhs);
?private:int _ix;int _iy;
};
?
//point 有什么東西編譯器已經知道,現在對destance做定義就可以了,在外面是普通函數,就上作用域
float Line::destance(const Point &lhs,const Point &rhs)
{return sqrt(pow(lhs._ix - rhs._ix ,2)+pow(lhs._iy - rhs._iy,2));
}
 

image-20240312162223639

補充:

前向聲明的用處:進行了前向聲明的類,可以以引用或指針的形式作為函數的參數,只要不涉及到對該類對象具體成員的訪問,編譯器可以通過。

(讓編譯器認識這個類,但是注意如果只進行前向聲明,這個類的具體實現沒有的話,無法使用這個類的對象,無法創建)

注意:友元的聲明要注意和函數的形式完全對應上。

友元類

如上的例子,假設類 Line 中不止有一個 distance 成員函數,還有其他成員函數,它們都需要訪問Point 的私有成員,如果還像上面的方式一個一個設置友元,就比較繁瑣了,可以直接將 Line 類設置為 Point 的友元類,在工作中這也是更常見的方法。

class Point {//...friend class Line;//...
};

在Point類中聲明Line類是本類的友元類,那么Line類中的所有成員函數中都可以訪問Point類的私有成員。一次聲明,全部解決。

image-20240312163304583

不可否認,友元將類的私有成員暴露出來,在一定程度上破壞了信息隱藏機制,似乎是種“副作用很大的藥”,但俗話說“良藥苦口”。好工具總是要付出點代價的,拿把鋒利的刀砍瓜切菜,總是要注意不要割到手指的。

友元的存在,使得類的接口擴展更為靈活,使用友元進行運算符重載從概念上也更容易理解一些,而且, C++ 規則已經極力地將友元的使用限制在了一定范圍內。

友元的特點

  1. 友元不受類中訪問權限的限制——可訪問私有成員

  2. 友元破壞了類的封裝性

  3. 不能濫用友元 ,友元的使用受到限制

  4. 友元是單向的——A類是B類的友元類,則A類成員函數中可以訪問B類私有成員;但并不代表B類是A類的友元類,如果A類中沒有聲明B類為友元類,此時B類的成員函數中并不能訪問A類私有成員

  5. 友元不具備傳遞性——A是B的友元類,B是C的友元類,無法推斷出A是C的友元類

  6. 友元不能被繼承——因為友元破壞了類的封裝性,為了降低影響,設計層面上友元不能被繼承

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

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

相關文章

位運算[找出唯一成對的數]

題目來源:藍橋云課 不用輔助儲存空間 import java.util.Random;public class T_01 {public class Util {public static void swap(int[] arr, int i, int j) {int temp arr[i];arr[i] arr[j];arr[j] temp;}public static void print(int[] arr) {for (int i 0; …

簡記_FPGA 硬件最小系統設計

一、FPGA板級設計的五要素 1.1、電源電路 核心電壓:一般為固定值 IO電壓:FPGA的IO分為多個bank,同一個bank的不同IO引腳電壓相同,不同bank的電壓可以不同 輔助電壓:除了核心電壓和IO電壓,FPGA工作所需的…

7.2 控件和組件

版權聲明:本文為博主原創文章,轉載請在顯著位置標明本文出處以及作者網名,未經作者允許不得用于商業目的 C#工具箱位于編輯窗口的左側,它默認內置了大量的控件和組件。控件一般派生于System.Windows.Forms.Control類,顯…

Spring Boot中接口數據字段為?Long?類型時,前端number精度丟失問題解決方案

Spring Boot中接口數據字段為 Long 類型時,前端number精度丟失問題解決方案 在Spring Boot中,當接口數據字段為 Long 類型時,返回頁面的JSON中該字段通常會被序列化為數字類型。 例如,一個Java對象中有一個 Long 類型的屬性 id …

OpenCV第2課 OpenCV的組成結構與圖片/視頻的加載及展示

1.OpenCV 的組成結構 2.OpenCV 的具體模塊 3. 圖像的讀取 4. 視頻的讀取 1.OpenCV 的組成結構 OpenCV 是由很多模塊組成的,這些模塊可以分成很多層: 最底層是基于硬件加速層(HAL)的各種硬件優化。再上一層是opencv_contrib 模塊所包含的OpenCV 由其他開發人員所貢獻的代…

安裝配置Tesseract-OCR

1,下載對應的可執行文件 在Tesseract OCR下載地址Index of /tesseract下載合適的版本安裝包,如下: 點擊安裝包進行安裝: 語言選擇英文: 如果需要識別中文,則可以在安裝過程中勾選下載中文語言包和腳本(也可以按需選擇繁體):

關于墻面涂鴉的視覺檢測與噴涂修復裝置研究(大綱)

公共場所墻面涂鴉視覺檢測與精準噴涂修復裝置研究 融合視覺識別與自動化噴涂的墻面維護解決方案 第一章 緒論 1.1 研究背景與意義 城市形象與秩序維護: 涂鴉對公共環境的影響(破壞美觀、傳遞不良信息)清除涂鴉的重要性(恢復原貌…

圖論 | 98. 所有可達路徑

98. 所有可達路徑 題目鏈接: 98. 所有可達路徑 思路 先創建鄰接矩陣,再深搜寫代碼是需要注意的是acm格式,輸入的格式要轉化為int,輸出要轉化為str,用map()實現。 dfs def dfs(grid,node,n,…

MCP+Hologres+LLM 搭建數據分析 Agent

LLM大模型在數據分析領域的挑戰 在數據分析領域,大模型(LLM)具備強大語言理解能力,NL2SQL等各類智能化工具也極大提升了數據分析人員的分析效率,但仍舊面臨不少挑戰: 傳統 LLM 缺乏實時數據接入能力&…

Categorical分布(分類分布):深度學習中的離散建模利器

Categorical分布:深度學習中的離散建模利器 引言 對于深度學習研究者來說,概率分布是模型設計和優化的基石。在許多生成模型中,如變分自編碼器(VAE)及其變種VQ-VAE(Vector Quantized Variational Autoenc…

Langchain 提示詞(Prompt)

基本用法 1. 基本概念 提示詞模板 是一個字符串模板,其中包含一些占位符(通常是 {variable} 形式的),這些占位符可以在運行時被實際值替換。LangChain 提供了多種類型的提示詞模板,以適應不同的使用場景。 2. 主要類…

centos7.9鏡像源及Python引入ssl問題處理

一、鏡像源修改 1. 備份原有的鏡像源配置文件 在修改之前,先備份現有的 CentOS-Base.repo 文件: sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2. 編輯鏡像源配置文件 使用文本編輯器(如 nano 或 vi)打開 /etc/yum.repos.d/Ce…

Java高頻面試之集合-17

hello啊,各位觀眾姥爺們!!!本baby今天來報道了!哈哈哈哈哈嗝🐶 面試官:JDK 8 對 HashMap 主要做了哪些優化呢?為什么要這么做? JDK 8 對 HashMap 的主要優化及原因 JDK…

計算機二級:函數基礎題

函數基礎題 第一題 rinput("請輸入半徑:") c3.1415926*r*2 print("{:.0f}".format(c))輸出: Type Error第二題 a7 b2 print(a%2)輸出 1第三題 ab4 def my_ab(ab,xy):abpow(ab,xy)print(ab,end"\n") my_ab(ab,2)prin…

C# 屬性(Property)?詳解

在 C# 中,?屬性(Property)? 是類或結構體中的成員,用于封裝對私有字段(稱為 ?backing field?)的訪問,提供更靈活和安全的數據操作方式。屬性通過 get 和 set 訪問器控制對數據的讀寫&#x…

iPhone 16如何翻譯文檔?文檔翻譯技巧、軟件推薦

在全球化的今天,跨語言交流變得越來越頻繁,而文檔翻譯更是成為許多人日常工作和學習中的重要需求。作為蘋果公司最新推出的旗艦機型,iPhone 16憑借其強大的硬件性能和豐富的軟件生態,為我們提供了多種便捷的文檔翻譯方式&#xff…

HRP方法全文總結與模型流程解析

背景與問題 傳統二次優化方法(如Markowitz的CLA)存在三大問題: 不穩定性:協方差矩陣的高條件數導致逆矩陣計算誤差放大,權重劇烈波動。 集中性:優化結果過度集中于少數資產,易受個體風險沖擊。…

解決項目一直在構建中的問題:以 IntelliJ IDEA 為例提高共享堆內存

在使用 IntelliJ IDEA 時,開發者可能會遇到項目長期處于構建狀態的問題。這種情況將嚴重影響開發效率。通常,這種問題的一個常見原因是構建進程所分配的堆內存不足。本文將以 IntelliJ IDEA 為背景,介紹如何通過提高共享堆內存來解決此問題&a…

金橙子刪除打標對象

注意在使用金橙子根據對象名稱刪除對象時要注意,每刪除一個對象,所有對象的索引都將改變。 如果你是用for去遍歷,再根據索引獲取打標對象名稱的話就會出現漏的掉的問題。 改進方法 1,將要刪除的對象找到后,統一存放在一個集合中。再根據這個要刪除的對象集合再一個個去遍…

JVM常見概念之條件移動

問題 當我們有分支頻率數據時,有什么有趣的技巧可以做嗎?什么是條件移動? 基礎知識 如果您需要在來自一個分支的兩個結果之間進行選擇,那么您可以在 ISA 級別做兩件不同的事情。 首先,你可以創建一個分支&#xff…