C++中友元(友元函數和友元類)的用法和功能

http://blog.csdn.net/adriano119/article/details/5914443/

采用類的機制后實現了數據的隱藏與封裝,類的數據成員一般定義為私有成員,成員函數一般定義為公有的,依此提供類與外界間的通信接口。但是,有時需要定義一些函數,這些函數不是類的一部分,但又需要頻繁地訪問類的數據成員,這時可以將這些函數定義為該函數的友元函數。除了友元函數外,還有友元類,兩者統稱為友元。友元的作用是提高了程序的運行效率(即減少了類型檢查和安全性檢查等都需要時間開銷),但它破壞了類的封裝性和隱藏性,使得非成員函數可以訪問類的私有成員。

友元函數??
?????? 友元函數是可以直接訪問類的私有成員的非成員函數。它是定義在類外的普通函數,它不屬于任何類,但需要在類的定義中加以聲明,聲明時只需在友元的名稱前加上關鍵字friend,其格式如下:
?????? friend 類型 函數名(形式參數);

?????? 友元函數的聲明可以放在類的私有部分,也可以放在公有部分,它們是沒有區別的,都說明是該類的一個友元函數。
?????? 一個函數可以是多個類的友元函數,只需要在各個類中分別聲明。
?????? 友元函數的調用與一般函數的調用方式和原理一致。

友元類??
?????? 友元類的所有成員函數都是另一個類的友元函數,都可以訪問另一個類中的隱藏信息(包括私有成員和保護成員)。???????
?????? 當希望一個類可以存取另一個類的私有成員時,可以將該類聲明為另一類的友元類。定義友元類的語句格式如下:
?????? friend class 類名;
?????? 其中:friend和class是關鍵字,類名必須是程序中的一個已定義過的類。

?????? 例如,以下語句說明類B是類A的友元類:
?????? class A
?????? {
????????????? …
?????? public:
????????????? friend class B;
????????????? …
?????? };
?????? 經過以上說明后,類B的所有成員函數都是類A的友元函數,能存取類A的私有成員和保護成員。

?????? 使用友元類時注意:
???????????? (1)?
友元關系不能被繼承。?
???????????? (2)?友元關系是單向的,不具有交換性。若類B是類A的友元,類A不一定是類B
的友元,要看在類中是否有相應的聲明。
???????????? (3)?友元關系不具有傳遞性。若類B是類A的友元,類C是B的友元,類C不一定是類A的友元,同樣要看類中是否有相應的申明

《windows環境多線程編程原理與應用》中解釋:

  如果將類的封裝比喻成一堵墻的話,那么友元機制就像墻上了開了一個門,那些得

  到允許的類或函數允許通過這個門訪問一般的類或者函數無法訪問的私有屬性和方   

  法。友元機制使類的封裝性得到消弱,所以使用時一定要慎重。

  ■ 友元類的說明

   將外界的某個類在本類別的定義中說明為友元,那么外界的類就成為本類的“朋  

   友”,那個類就可以訪問本類的私有數據了。

   class Merchant

????? {

????????? private :

???????????? int m_MyMoney;

???????????? int m_MyRoom;

???????????? … …

????????? Public:

???????????? Friend class Lawyer;

???????????? Int getmoney();

???????????? … …

????? };

????? Class Lawyer

???? {

??????? Private:

????????? … …

??????? Public:

???????? … …

???? };

???? 只有你賦予某個類為你的友元時,那個類才有訪問你的私有數據的權利。

  ■ 說明一個函數為一個類的友元函數則該函數可以訪問此類的私有數據和方法。定

   義方法是在類的定義中,在函數名前加上關鍵字friend.

挑戰30天C/C++》這樣解釋:

  在說明什么是友元之前,我們先說明一下為什么需要友元與友元的缺點:?
通常對于普通函數來說,要訪問類的保護成員是不可能的,如果想這么做那么必須把類的成員都生命成為public(共用的),然而這做帶來的問題遍是任何外部函數都可以毫無約束的訪問它操作它,c++利用friend修飾符,可以讓一些你設定的函數能夠對這些保護數據進行操作,避免把類成員全部設置成public,最大限度的保護數據成員的安全。?
友元能夠使得普通函數直接訪問類的保護數據,避免了類成員函數的頻繁調用,可以節約處理器開銷,提高程序的效率,但所矛盾的是,即使是最大限度大保護,同樣也破壞了類的封裝特性,這即是友元的缺點,在現在cpu速度越來越快的今天我們并不推薦使用它,但它作為c++一個必要的知識點,一個完整的組成部分,我們還是需要討論一下的。?
在類里聲明一個普通數學,在前面加上friend修飾,那么這個函數就成了該類的友元,可以訪問該類的一切成員。

???下面我們來看一段代碼,看看我們是如何利用友元來訪問類的一切成員的

???????//程序作者:管寧?
//
站點:www.cndev-lab.com?
//
所有稿件均有版權,如要轉載,請務必著名出處和作者?
#include <iostream>?
using?namespace?std;?
class?Internet?
{?
public:?
Internet(char?*name,char?*address)?//?
改為:internet(const char *name , const char *address)
{?
strcpy(Internet::name,name);?
strcpy(Internet::address,address);?
}?
friend?void?ShowN(Internet &obj);???//
友元函數的聲明?
public:?
//?改為:private
char?name[20];?
char?address[20];?
};?
void?ShowN(Internet &obj)????????//
函數定義,不能寫成,void Internet::ShowN(Internet &obj)?
{?
cout<<obj.name<<endl; ?????????//
可訪問internet類中的成員
}?
void?main()?
{?
Internet a("
中國軟件開發實驗室","www.cndev-lab.com");?
ShowN(a);?
cin.get();?
}?

上面的代碼通過友元函數的定義,我們成功的訪問到了a對象的保護成員name,友元函數并不能看做是類的成員函數,它只是個被聲明為類友元的普通函數,所以在類外部函數的定義部分不能夠寫成void Internet::ShowN(Internet &obj),這一點要注意。

================================================================================

實例:

分別定義一個類A和類B ,各有一個私有整數成員變量通過構造函數初始化;類A有一個成員函數Show(B &b)用來打印A和B的私有成員變量,請分別通過友元函數和友元類來實現此功能。

?

用友元類 和 友元函數做出來的


#include <iostream>

using namespace std;

class B;
class A;
void Show( A& , B& );

class B
{
private:
int tt;
friend class A;
friend void Show( A& , B& );

public:
B( int temp = 100):tt ( temp ){}

};


class A
{
private:
int value;
friend void Show( A& , B& );

public:
A(int temp = 200 ):value ( temp ){}

void Show( B &b )
{
? cout << value << endl;
? cout << b.tt << endl;?
}
};

void Show( A& a, B& b )
{
cout << a.value << endl;
cout << b .tt << endl;
}

int main()
{
A a;
B b;
a.Show( b );
Show( a, b );

????? return 0;
}


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

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

相關文章

線程的終止分離

1.線程的終止 注意該函數是針對用戶級別的, 其中 retal 必須指向一個全局變量, 或者是一個 malloc 分配的, 因為如果是線程的局部變量, 當該線程退出時, 其他線程不能得到這個變量, 因為線程的局部變量各自私有 2. 現成的取消 其中thread是線程的 tid 3.線程的等待與分離 (1)…

UVa10082

【題目描述】 傳送門 【題目分析】 同樣是一道模擬&#xff0c;但是如何巧妙快速的解決仍然不簡單。通過這道題告訴我們對于復雜確定的對應關系我們要靈活運用常量數組。 同時還需要注意的一個小問題就是字符串數組中的"//"指的是轉義后的單斜杠&#xff0c;如果只…

C語言中的深拷貝和淺拷貝

http://www.cnblogs.com/zhanggaofeng/p/5421804.html C語言中的深拷貝和淺拷貝 //C語言中的深拷貝和淺拷貝 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h>typedef struct _student{char name[30];char *title;…

死鎖的產生和避免

1.死鎖產生的四個必要條件 (1)互斥條件&#xff1a;資源是獨占的且排他使用&#xff0c;進程互斥使用資源&#xff0c;即任意時刻一個資源只能給一個進程使用&#xff0c;其他進程若申請一個資源&#xff0c;而該資源被另一進程占有時&#xff0c;則申請者等待直到資源被占有者…

UVa401

【題目描述】 傳送門 【題目描述】 嘻嘻&#xff0c;自己做直接AC還是比較開心的。當然有一部分原因是之前看書的時候詳細看過這個題的代碼&#xff0c;但是這已經快一年了&#xff0c;應該說做出這道題憑借的是自己的能力吧。回過身去看了一下書中的代碼發現自己寫的不算復…

gethostbyname() 函數說明

https://www.cnblogs.com/cxz2009/archive/2010/11/19/1881611.html gethostbyname()函數說明——用域名或主機名獲取IP地址 包含頭文件#include <netdb.h>#include <sys/socket.h>函數原型struct hostent *gethostbyname(const char *name);這個函數的傳入值是域…

求解迷宮最短路徑

1. 多通路迷宮初始化 先構建一個多通路迷宮,并且對其初始化 void MazeInitShortPath(Maze* maze) {if(maze NULL){return;}int row 0;int col 0;for(; row < MAX_COL; row){for(col 0; col < MAX_COL; col){maze -> map[row][col] Map[row][col];}printf("…

UVa340

【題目描述】 傳送門 【題目分析】 題目理解以后十分簡單&#xff0c;但是這題面實在讓人自閉&#xff0c;這么簡單的題目啦啦啦啦說了那么多&#xff0c;實在是看不懂。&#xff08;幸虧我看了書理解了題目的意思&#xff0c;要不然。。&#xff09;還是要鍛煉自己的讀題能…

C語言:結構體中一級指針和二級指針的創建與釋放示例

http://blog.csdn.net/Bixiwen_liu/article/details/53610952 這幾天把C語言鞏固了一下&#xff0c;作為一門最基本的編程語言&#xff0c;C語言還是相當基礎和非常重要的&#xff0c;個人認為C語言還是很有必要學好吃透的。 今天寫的話題是結構體結構體中一級指針和二級指針的…

帶環迷宮求最短路徑

前面介紹了簡單的迷宮求解問題, 今天我們就對帶環迷宮求出它的最短路徑 1.首先來看一個帶環迷宮的簡單地圖 在這張迷宮地圖中,我們規定入口點的位置entry的坐標是 (0, 1), 同時, 我們給入口點傳一個非法坐標,作為入口點的前一個位置(-1, -1). 接下來的思路就和上一篇的思路是一…

UVa1583

【題目描述】 傳送門 【題目分析】 我以為很簡單就寫了一個暴力沒有想到超時了。應該是T是非常大的所以必須得打表&#xff0c;將所有的結果都儲存起來然后直接輸出。 以后遇到這種可以一下算出所有結果的多組數據最好還是算出所有的結果然后再輸出答案。 【AC代碼】 #inc…

C 結構體嵌套一級指針 二級指針 動態分配內存

https://blog.csdn.net/xielinhua88/article/details/51364623 點擊打開鏈接 #define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h> //結構體嵌套一級指針 二級指針 動態分配內存 typedef struct _Teacher { int ag…

線程的同步與互斥

1. 互斥量 在Linux 下線程使用的都是局部變量, 而我們知道, 每一個線程都獨立擁有自己的一個棧, 而這些局部便令就在棧中,而線程的創建就是為了實現通信, 此時線程之間無法共享這些變量 ????為了使得線程之間能夠共享數據, 一次我們可以創建一個全局變量, 此時線程都在進程…

二級指針與指針數組的關系

http://blog.csdn.net/shuaishuai80/article/details/6129742 #include <stdio.h> void test(char *argv[]); int main(void) { char *argv[3]{{"abcdefg"},{"1234567"},{"q1w2e3r"}}; test(argv); /*調用指針數組…

UVa1584

【題目描述】 傳送門 【題目分析】 也是一道簡單的模擬題&#xff0c;1A嘿嘿嘿。 再看書發現和書上的做法差不多。 【AC代碼】 #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<cstd…

cf#582div3 D——暴力

【題目描述】 The only difference between easy and hard versions is the number of elements in the array.You are given an array a consisting of n integers. In one move you can choose any ai and divide it by 2 rounding down (in other words, in one move you c…

C語言 可變參數

http://www.cnblogs.com/zhanggaofeng/p/6434554.html //可變參數 #include <stdio.h> #include <stdlib.h> #include <string.h> //引用頭文件 #include <stdarg.h>/* va_list用于聲明一個變量&#xff0c;我們知道函數的可變參數列表其實就是一個字符…

UVa1585

【題目描述】 傳送門 【題目分析】 氵 【AC代碼】 #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<cstdlib> #include<set> #include<map> #include<vector>u…

c語言經典算法——查找一個整數數組中第二大數

https://www.cnblogs.com/dootoo/p/4473958.html 題目&#xff1a; 實現一個函數&#xff0c;查找一個整數數組中第二大數。 算法思想&#xff1a; 設置兩個變量max1和max2&#xff0c;用來保存最大數和第二大數&#xff0c;然后將數組剩余的數依次與這兩個數比較&#xff0c;如…

進程間關系和守護進程

一. 進程組/作業/會話 1.進程組 每一個進程除了有一個進程ID之外, 還屬于一個進程組. 進程是一個或多個進程的集合. 通常, 它們與同一個作業向關聯, 可以接收來自同一個終端下的各種命令,信號. 每一個進程組都有唯一的進程組 ID. 每一個進程組都可以有一個組長進程. 組長進程的…