C++ 友元

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

一 同類對象間無私處

MyString::MyString(const MyString & other) 
{
    int len = strlen(other._str);
    this->_str = new char[len+1];
    strcpy(this->_str,other._str); 
}

二 異類對象間有友元

友元目的本質,是讓其它不屬于本類的成員(全局函數,其它類的成員函數),成為類的成員而具備了本類成員的屬性。

友元函數

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

friend 類型 函數名(形式參數);

一個函數可以是多個類的友元函數,只需要在各個類中分別聲明。

全局函數作友元函數

#include <iostream>
#include <cmath>
using namespace std;
class Point
{
public:
    Point(double xx, double yy)
    {
        x = xx;
        y = yy;
    }
    void Getxy();
    friend double Distance(Point &a, Point &b);

private:
    double x, y;
};
void Point::Getxy()
{
    cout << "(" << x << "," << y << ")" << endl;
}
double Distance(Point &a, Point &b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}
int main(void)
{
    Point p1(3.0, 4.0), p2(6.0, 8.0);
    p1.Getxy();
    p2.Getxy();
    double d = Distance(p1, p2);
    cout << "Distance is" << d << endl;
    return 0;
}

類成員函數作友元函數

#include <iostream>
#include <cmath>
using namespace std;

class Point;//前向聲明

//由于ManagePoint中的函數需要作為Point中的友元函數中,故ManagePoint需要先定義
class ManagePoint
{
public:
    double Distance(Point &a, Point &b);
};

/*
若放在這里會報錯
double ManagePoint::Distance(Point &a, Point &b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}
*/

class Point
{
public:
    Point(double xx, double yy)
    {
        x = xx;
        y = yy;
    }
    void Getxy();
    ////將一個類的成員函數作為另一個類的友元函數時,函數名應該用該函數所屬的類名字加以限定。
    friend double ManagePoint::Distance(Point &a, Point &b);

private:
    double x, y;
};
//這里引用了類Point的私有成員x和y,故需要放在類Point的定義之后(若放在ManagePoint和Point之間,會報錯)
double ManagePoint::Distance(Point &a, Point &b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}

void Point::Getxy()
{
    cout << "(" << x << "," << y << ")" << endl;
}

int main(void)
{
    Point p1(3.0, 4.0), p2(6.0, 8.0);
    p1.Getxy();
    p2.Getxy();
    ManagePoint mp;
    double d=mp.Distance(p1,p2);
    cout << "Distance is" << d << endl;
    return 0;
}

說明:關于前向聲明

前向聲明,是一種不完全型(forward declaration)聲明,即只需提供類名(無需提供 類實現)即可。正因為是(incomplete type)功能也很有限:

  • 不能定義類的對象。
  • 可以用于定義指向這個類型的指針或引用。
  • 用于聲明(不是定義),使用該類型作為形參類型或者函數的返回值類型。

友元類

友元類的所有成員函數都是另一個類的友元函數,都可以訪問另一個類中的隱藏信息(包 括私有成員和保護成員)。
當希望一個類可以存取另一個類的私有成員時,可以將該類聲明為另一類的友元類。定義 友元類的語句格式如下:

friend class 類名;
其中:friend 和 class 是關鍵字,類名必須是程序中的一個已定義過的類。
例如,以下語句說明類 B 是類 A 的友元類:
class A {
        ...
public:
        friend class B;
        ... 
};

經過以上說明后,類 B 的所有成員函數都是類 A 的友元函數,能存取類 A 的私有成員和 保護成員。

class A
{
public:
    inline void Test()
    {
    }

private:
    int x, y;
    friend Class B;
};
class B
{
public:
    inline void Test()
    {
        A a;
        printf("x=%d,y=%d".a.x, a.y);
    }
}

注意:這里友元類放置的位置沒有嚴格要求,相比于類類成員函數作友元函數。

論友元

聲明位置

友元聲明以關鍵字 friend 開始,它只能出現在類定義中。因為友元不是授權類的成員, 所以它不受其所在類的聲明區域 public private 和 protected 的影響。通常我們選擇把所有友元聲明組織在一起并放在類頭之后.

友元的利弊

友元不是類成員,但是它可以訪問類中的私有成員。友元的作用在于提高程序的運行效率, 但是,它破壞了類的封裝性和隱藏性,使得非成員函數可以訪問類的私有成員。不過,類的訪問權限確實在某些應用場合顯得有些呆板,從而容忍了友元這一特別語法現象。

注意事項

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

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。