天天看點

友元 基礎詳解版 (友元函數、友元類、友元非成員函數和友元成員函數)

友元

一般來說,類的公有成員能夠在類外通路,私有的成員隻能被類的其他成員函數通路。

在C++中,可以定義友元,如果某一個函數定義為類的友元,則該函數就可以通路該類的私有函數。也可以把一個類定義為另一個類的友元。

友元函數

如果在某個類的定義中用

friend

聲明了一個外部函數(或者是其他類的成員函數,既可以是

public

型,也可以是

private

型)後,這個外部函數稱為類的友元函數。

C++提供一種允許外部類和函數存取類的私有成員和保護成員的輔助方法,即将它們聲明為一個給定類的友元(或友元函數),使其具有類成員函數的通路權限,但友元本身不是類的成員,它不屬于任何類。

使用:

  • 關鍵字:

    friend

    開頭的函數原型,聲明可以放在類的私有部分,或者公有部分,無差別,都說明是該類的一個友元函數,但它不是該類的成員函數,不屬于任何類;
  • 友元函數的定義,可以在類的内部或外部;
  • 在類外定義友元函數時,與普通函數的定義一樣,不應在函數名前用類名加以限制。是以友元函數不像成員函數那樣在調用時使用對象名,友元函數要多類的成員進行通路,必須在參數表中顯式指明要通路的對象。
  • 友元函數是能通路類的所有成員的普通函數,一個函數可以是多個類的友元函數,隻需要在各個類中分别聲明;
  • 調用與一般函數的調用方式及原理一緻;
  • C++不允許将構造函數、析構函數和虛函數聲明為友元函數

友元的非成員函數

友元函數是可以直接通路類的私有成員的非成員函數。它是定義在類外的普通函數,需要在類的定義中加以聲明,聲明時隻需在友元的名稱前加關鍵字**

friend

**,

非成員函數的友元函數有如下特點。

  • 在類内隻需對函數進行聲明,聲明位置沒有要求,可以出現在類的任何地方,包括在

    private

    public

    部分。
  • 函數定義要放在類外,具體定義位置沒有要求。
  • 友元函數不能直接通路類的成員,必須通過通路對象來實作。為此,必須傳遞類對象作為函數參數,采用傳值、傳指針或傳引用方式均可,出于對程式執行效率的考慮,建議使用類對象的引用作為參數。
  • 友元函數不是類的成員函數,是以友元函數的實作和普通函數一樣,在實作時不用作用域限定符“::”訓示屬于哪個類,隻有成員函數才使用“::”作用域符号。
  • 一個函數可以同時作為多個類的友元函數。

非成員形式的友元函數代碼如下所示。

//友元函數的例子
#include <iostream>
#include <math.h>
using namespace std;
class Point
{
public:
    Point(double i, double j)                                  //構造函數,帶預設參數值
    {
        x = i;
        y = j;
    }
    void disp()
    {
        cout<<"("<<x<<","<<y<<")"<<endl;
    }

private:
    double x;
    double y;
    friend double dis(Point &a, Point &b);                      //友元函數的聲明
};

double dis(Point &a, Point &b)                                 //類外,友元函數的定義
{
    double dx=a.x-b.x;                                         //友元函數可以通路類的private成員
    double dy=a.y-b.y;

    return sqrt(dx*dx+dy*dy);
}

int main()
{
    Point p1(3.0,4.0);                                        //聲明兩個Point類的對象p1和p2;
    Point p2(6.0,8.0);
    p1.disp();                                                //顯示p1和p2點的資訊
    p2.disp();                    
   
    cout<<"Distance is "<<dis(p1,p2)<<endl;                   //友元函數的調用
    return 0;
}
           

友元的成員函數

除了一般的函數可以作為類的友元外,一個類的成員函數也可以作為另一個類的友元。這樣的函數不僅可以通路本類的所有成員,還可以通路其友元類的所有成員。需要注意的是,當在一個類中的某個成員函數定義為另一個類的友元函數時需要首先定義此類。

例如,要定義類A的某個函數為類B的友元函數,那麼需要先定義類B,然後再進行類A的成員函數與B友元的定義。

對于一個友元成員來說,它不僅可以通路自己所在類中的私有成員和公有成員,同時還可以的一個對聲明為友元類的類的成員進行通路。使用友元成員可以使得兩個類之間出現互相通路“門”。這樣解決了由于類的保護機制而出現的其他類絕對不允許通路的情況。

成員形式的友元函數代碼如下所示。

//友元函數的例子
#include <iostream>
using namespace std;
class Point;                                                 //聲明Point類:在line類的dis函數中傳遞對象參數。是以必須在line類之前對Point類                                                              //聲明,且由于PoInt類的定義在後面,隻能對Point對象采取傳引用或傳指針處理;
class line                                                    //友元函數所在的類必須標明義,即line類必須定義在Point類前面
{
    public:
    double dis(Point &p1, Point &p2);                         //友元函數的原型,作為line類的成員函數
};

class Point
{
public:
    Point(double i, double j)                                  //構造函數,帶預設參數值
    {
        x = i;
        y = j;
    }
    void disp()
    {
        cout<<"("<<x<<","<<y<<")"<<endl;
    }

private:
    double x;
    double y;
    friend double line::dis(Point &a, Point &b);               //友元的聲明
};

double line::dis(Point &a, Point &b)                           //line類内的成員函數dis()的實作,作為Point類的友元函數;
{
    double dx=a.x-b.x;                                         //友元函數可以通路類的private成員
    double dy=a.y-b.y;

    return sqrt(dx*dx+dy*dy);
}

int main()
{
    line line1;                                               //聲明一個line類的對象line1;
    Point p1(3.0,4.0);                                        //聲明兩個Point類的對象p1和p2;
    Point p2(6.0,8.0);
    p1.disp();                                                //顯示p1和p2點的資訊
    p2.disp();                    
   
    cout<<"Distance is "<<line1.dis(p1,p2)<<endl;                   //友元函數的調用
    return 0;
}
           
友元 基礎詳解版 (友元函數、友元類、友元非成員函數和友元成員函數)

友元類

友元類的所有成員函數都是另一個類的友元函數,都可以通路另一個類中的隐藏資訊(包括私有成員和保護成員)。

定義友元類的語句格式如下:

其中

:friend

class

是關鍵字。類名必須是程式中的一個已定義過的類。

//類B是類A的友元類
class A
{
Public:
    friend class B;
};
           

友元類B中的所有成員函數都是類A的友元函數,能存取類A的私有成員和保護成員。

當把B聲明為A類的友元類時,并不一定要求先定義B,隻要先對其進行聲明即可,這點差別于友元的成員函數。

  • 友元關系是單向的,不具有交換性。若類X是類Y的友元,類Y不一定是類X的友元,要看在類中是否有相應的聲明。
  • 友元關系不具有傳遞性。若類X是類Y的友元,類Y是Z的友元,類X不一定是類Z的友元,同樣要看類中是否有相應的申明。
  • 友元關系不能被繼承。