C/C++友元

5814 ワード

(1)概念
(1)なぜ友元を使うのか
クラス間のデータ共有を実現する際、システムのオーバーヘッドを低減し、効率を向上させる.クラスAの関数がクラスBのメンバー(たとえば、スマートポインタクラスの実装)にアクセスする場合、クラスAの関数はクラスBの友元関数である.
すなわち、他のクラスのメンバー関数がクラスのプライベート変数に直接アクセスできるように、外部のクラスまたは関数がクラスのプライベート変数と保護変数にアクセスし、2つのクラスが同じ関数を共有できるようにします.
実際には、(1)演算子をリロードする場合、(2)2つのクラスがデータを共有する場合、(2)演算子をリロードする必要がある場合の2つのケースがあります.
利点:効率を高めることができて、表現が簡単で、はっきりしています;欠点:友元関数はパッケージメカニズムを破り、できるだけ友元関数を使用しないで、やむを得ない場合を除いて友元関数を使用しない.
友元関数はクラス外の関数であるため、その宣言はクラスのプライベートセグメントまたは共通セグメントに置くことができ、区別がなく、オブジェクトやポインタを通過する必要がなく、友元関数を直接呼び出すことができます.
(2)友元分類
(1)一般クラスのメタ関数
class INTEGER
{
    friend void Print(const INTEGER& obj);//      
};

void Print(const INTEGER& obj)
{
}

void main()
{
    INTEGER obj;
    Print(obj);//    
}

(2)友元クラス(すべてのメンバー関数が友元関数)
class girl;

class boy
{
public:
  void disp(girl &);
};
//  disp()  boy     ,   girl     
void boy::disp(girl &x)
{
    //    , boy     disp ,  girl   ,    girl     
    cout<<"girl's name is:"<",age:"<class girl
{
private:
  char *name;
  int age;
  //   boy  girl   
  friend class boy;
};

(3)詳細な例を見る
//point.h  

class Point {

private:
    int x, y;

public:
    Point(int x, int y) {
        this->x = x;
        this->y = y;
    }

    void getXY();

    friend int distance(Point &a, Point &b);
    friend class You;
};

class You {
public:
    double Multi(Point &a) {
        return a.x * a.y + 1;
    }
};

void showPoint();
//point.cpp  

#include 
#include "point.h"
using std::cout;
using std::endl;

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

int distance(Point &a, Point &b) {
    int x = a.x + b.x;
    int y = b.y + b.y;
    return x + y;
}

void showPoint() {
    Point p1(2, 3), p2(4, 5);

    p1.getXY();

    cout << distance(p1, p2) << endl;

    You you;
    cout << you.Multi(p1) << endl;
}

(4)部分オペレータリロードなぜ友元を使用するのか
書き方フォーマット:戻り値operator演算子(パラメータリスト){}
オペレータのリロードは優先度を変更せず、操作数の数は変更されません.
演算子を再ロードする場合、関数宣言はクラス内とクラス外で区別され、例えば+-*/など2つのオペランドを必要とする演算子;
(1)クラス外で宣言:クラスの外部で宣言された場合、パラメータリストは2つのパラメータであり、最初のパラメータは演算子の左側のオペランドであり、2番目のパラメータはオペレータの右側のオペランドである.
classType operator+(classType& left, classType& right);

(2)クラス内、すなわちクラスのメンバー関数を宣言する.
classType operator+(classType& right);

1番目のオペランドはオペレータを呼び出すオブジェクトの参照であり、2番目のオペランドは伝達されたパラメータである.
だから重荷<
ostream& operator<const classType& obj);

最初のパラメータは、演算子の最初のオペランドですが、クラスオブジェクトではありません.したがって、クラス演算子がリロードされたときにクラスの内部に書き込まれると、クラス内のpublic以外の変数または関数にアクセスするために、友元関数として宣言する必要があります.
friend ostream& operator<const classType& obj);
//  
std::ostream & operator<std::ostream & os, const Time & t) {
    os << t.hours << " hours, " << t.minutes << " minutes";
    return os;
}