C++友元


友元是C++提供的一種破壞數據隱蔽和封裝的機制

1.友元函數

友元函數是在類中使用關鍵字friend修飾的非成員函數

1.1友元普通函數

定義與概念
  • 友元函數是一個普通的函數
  • 友元普通函數在實現時,不需要類名的限定;在調用時,也不需要由實例來調用
示例代碼
#include <iostream>
#include <cmath>
using namespace std;

class Point{
public:
    Point(int x = 0,int y = 0):x(x),y(y){}
    int getX(){ return x;}//內聯函數
    int getY(){ return y;}
    void showData();
    friend float dist(Point &p1,Point &p2);//聲明友元函數
private:
    int x,y;
};

//普通成員函數的實現,需要類名限定
void Point::showData(){
    cout << "x: " << x << ", y: " << y << endl;
}

//因為友元函數是非成員函數,所以不需要類名限制
float dist(Point &p1,Point &p2){
    double x = p1.x - p2.x;
    double y = p1.y - p2.y;
    return static_cast<float>(sqrt(x*x + y*y));
}

int main()
{
    Point p1(1,1),p2(4,5);
    p1.showData();
    p2.showData();
    //調用友元普通函數時,也不需要由類的實例來調用
    cout << "the distance is : " << dist(p1,p2) << endl;
    return 0;
}

1.2友元成員函數

定義與概念
  • 友元函數是其它類的成員函數
  • 必須先定義包含成員函數的類(比如說A),再在另外一個類(比如說B)中將該成員函數聲明為友元函數。此時雖然這個友元函數是A的成員函數,該友元函數仍然稱為非成員函數(對於B來說)
示例代碼
#include <iostream>
#include <cmath>
using namespace std;


//前向引用聲明,否則報錯 error: 'Point' does not name a type
class Point;

class Line{
public:
    //這時不能使用這樣的形式進行初始化:Line(Point p1,Point p2):p1(p1),p2(p2){}
    //因為此時Point的結構尚未定義,error: field 'p1' has incomplete type
    Line(Point p1,Point p2);
    Point& getP1(); //把引用當做函數返回值
    Point& getP2();
    float dist();
private:
    //不可以這樣定義成員變量:Point p1,p2;因為此時Point結構尚不完善
    Point &rp1,&rp2;//類(引用)的組合
};

class Point{
public:
    Point(int x = 0,int y = 0):x(x),y(y){}
    int getX(){ return x;}//內聯函數
    int getY(){ return y;}
    void showData();
    //聲明友元成員函數
    friend float Line::dist();
private:
    int x,y;
};

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

//Line類函數的延遲實現開始

//當一個類的成員變量是引用時,需要在初始化列表中初始化引用
//否則報錯:error: uninitialized reference member
Line::Line(Point p1,Point p2):rp1(p1),rp2(p2){}
Point& Line::getP1(){
     return rp1;
}
Point& Line::getP2(){
     return rp2;
}
float Line::dist(){
    double x = rp1.x - rp2.x;
    double y = rp1.y - rp2.y;
    return static_cast<float>(sqrt(x*x + y*y));
}
//Line類函數的延遲實現結束


int main()
{
    Point p1(1,1),p2(4,5);
    p1.showData();
    p2.showData();
    Line line(p1,p2);
    cout << "the distance is : " << line.dist() << endl;
    return 0;
}

2.友元類

定義與概念

示例代碼

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

class Point{
public:
    Point(int x = 0,int y = 0):x(x),y(y){}
    int getX(){ return x;}//內聯函數
    int getY(){ return y;}
    void showData();
    //聲明友元類,否則編譯不通過,error: 'int Point::x' is private
    friend class Line;
private:
    int x,y;
};

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


class Line{
public:
    Line(Point p1,Point p2):p1(p1),p2(p2){}
    Point getP1(){ return p1;}
    Point getP2(){ return p2;}
    float dist();
private:
    Point p1,p2;//類的組合
};

float Line::dist(){
    double x = p1.x - p2.x;
    double y = p1.y - p2.y;
    return static_cast<float>(sqrt(x*x + y*y));
}

int main()
{
    Point p1(1,1),p2(4,5);
    p1.showData();
    p2.showData();
    Line line(p1,p2);
    cout << "the distance is : " << line.dist() << endl;
    return 0;
}

3.友元的性質

  • 友元關系是不能傳遞的,如A是B的友元,B是C的友元,但A不是C的友元
  • 友元關系是單向的,A是B的友元,A可以訪問B的私有屬性,反之不成立
  • 友元關系是不被繼承的,A是B的友元,但A的派生類不是B的友元

4.總結

  • 友元是一種破壞數據隱蔽和封裝的機制,這是它的用處也是它的壞處。應該盡量避免使用友元
  • 示例代碼
#include <iostream>
#include <cmath>
using namespace std;

class Point{
public:
    Point(int x = 0,int y = 0):x(x),y(y){}
    int getX(){ return x;}//內聯函數
    int getY(){ return y;}
    void showData();
    float dist(Point p);
private:
    int x,y;
};

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

//通過這樣的方式,可以避免使用友元
float Point::dist(Point p){
    double x = p.x - this->x;
    double y = p.y - this->y;
    return static_cast<float>(sqrt(x*x + y*y));
}

int main()
{
    Point p1(1,1),p2(4,5);
    p1.showData();
    p2.showData();
    cout << "the distance is : " << p1.dist(p2) << endl;
    return 0;
}

5.補充

5.1前向聲明

  • 在C++里面可以聲明一個類而不定義它。這個聲明被稱為前向聲明(forward declaration)。
  • 在聲明之后,定義之前,這個類是一個不完全類型(incompete type),即已知它是一個類型,但不知道包含哪些成員,具有哪些操作。
  • 不完全類型只能以有限方式使用,不能定義該類型的對象,不完全類型只能用於定義指向該類型的指針及引用,或者用於聲明(而不是定義)使用該類型作為形參類型或返回類型的函數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM