C++友元関数(クラス)の使い方

4767 ワード

1,friendは1つの友元friendが一般的に1つの申明式であり、1つのクラスの内部に位置し、1つのクラスまたは1つの関数がそのクラスの友元であることを申明する.friendはメンバー関数を定義するわけではないので、friendはpublic、protected、privateの前に置いてもいいです.まったく同じです.友元として、そのクラスまたはその関数の内部でこのクラスにアクセスできるプライベートメンバー(インタフェースを介して渡されたクラス、および関数体の中のクラス、メンバー関数のようにプライベートメンバーにアクセスできる)を表すと、あなたと友达の間には何も隠されていないのではないでしょうか.例:
class A
{
public:
A(int _a) : a(_a) {}
friend void test(A&);
friend class B;
private:
int a;
};
void test(A& x)
{
x.a=100;//       a      
}
class B
{
public:
void foo();
};

friend宣言式が一般的な非テンプレートクラスまたは関数である場合、ここでは最初の宣言とすることができる.クラスについては、明示式のみ、関数については定義式のみです.
class A
{
public:
A(int _a) : a(_a) {}
friend void test(A& x)
{
x.a = 100;//  ::test()    
}
friend class B;
private:
int a;
};

注意関数の定義式はクラス内に配置されますが、メンバー関数ではありません.制限された定義形式を省略すると、グローバル関数になります.:test()です.もちろん、別のクラスのメンバー関数を友元として宣言することもできます.たとえば、次のようにします.
class A
{
public:
A(int _a) : a(_a) {}
friend void B::foo();
private:
int a;
};

総じて、クラスAのプライベートメンバーにどこでアクセスしたいかは、クラスAにその場所の説明式を書いてfriendキーワードを付けます.これは一般的な状況で、簡単ですが、パッケージの初心を破壊するので、できるだけ少なくします.Effective C++には、クラス定義の2元オペレータを適用し、オペランドを暗黙的に変換したい場合は、グローバル関数を定義し、クラスの友元を明示します.2、テンプレート関数は友元としてテンプレート関数を与えます.これはテンプレートであり、関数ではありません.
template<typename T>
void foo1(T);

foo 1をあるクラスの友元として定義する場合,テンプレートパラメータTをインスタンス化したり,演繹可能な申明式を与えたりし,演繹可能であっても一対の括弧を省くことはできない.次のようになります.
class A
{
public:
friend void foo1<char>(char);
friend void foo1<>(double);
};
       :::
class A
{
public:
friend void ::foo1(char);
};

もちろん、一般的な関数がこの形式を持っている場合は、テンプレート関数マッチングよりも優先されます.最後に、ここの申明式は定義式ではなく、申明(定義)まで行わなければならない.3,テンプレートクラスの友元テンプレートクラスでも2の友元を明らかにすることができるが,テンプレートクラスにはテンプレートパラメータがあり,このテンプレートパラメータを利用した友元が明らかになれば,この場合である.
template<typename T>
class A
{
public:
friend void foo1<T>(T);
};

しかし,ここではfoo 1がここで可視であること,すなわち初の申明式ではないことを要求しなければならない.テンプレートパラメータを使用しない場合は、興味深い状況になります.
template<typename T>
class A
{
public:
friend void foo(){}
};

ここでは定義式であり、foo()関数はテンプレートクラスの友元であり、このテンプレートクラスが現れると::foo()も現れる、すなわち:
A<int> a1;// ::foo()    
A<char> a2;// ::foo()     ,   C++      

4,Friendテンプレートこのクラスの一連の関数を定義する場合は、Friendテンプレートを使用します.テンプレートの説明式と似ていますが、template<>の後にfriendキーワードが追加されています.
class A
{
public:
template<typename T>
friend void foo();
};

5、定義式にできるかどうか
定義式として使用できる場合は、テンプレートパラメータのリストがなく、カッコが1対もありません.テンプレート申明式であれば、初回申明ではなく、その場所で可視でなければならない.
6、完全な例
template<typename T>
class Rat
{
public:
Rat(T _a, T _b) : a(_a), b(_b) {}
friend Rat<T> operator*<T>(Rat<T>&,Rat<T>&);
private:
T a,b;
};
template<typename T>
Rat<T> operator*(Rat<T> & x, Rat<T> & y)
{
return Rat<T>(x.a*y.a,x.b*y.b);
}

RatはTタイプの有理数クラスであり、その乗算を定義し、グローバル関数を定義し、友元であることを明らかにし、この関数もテンプレートであるべきであり、上記のようなプログラムがコンパイルされることを望んでいる.friend式の前にoperator*()の申明がないので、ここでは初申明ではなく、前に申明式を付けなければなりません.
template<typename T>
Rat<T> operator*(Rat<T> & x, Rat<T> & y);

その前にRatの申明もなく、加えて:
template<typename T>
class Rat;

コンパイルするか、友元テンプレートに変更します.
template<typename T>
class Rat
{
public:
Rat(T _a, T _b) : a(_a), b(_b) {}
template<typename U>
friend Rat<U> operator*(Rat<U>&,Rat<U>&);
private: 
T a,b;
};
template<typename T>
Rat<T> operator*(Rat<T> & x, Rat<T> & y)
{
return Rat<T>(x.a*y.a,x.b*y.b);
}

些細な違いがあって、Ratは一連の友元operator*を明らかにして、もちろん必要ありません.operator*だけで十分ですが、形式的には簡単です.もう1つのもっと簡単な形式は、定義式を中に入れて、まさにEffective C++で使用する方法です.
template<typename T>
class Rat
{
public:
Rat(T _a, T _b) : a(_a), b(_b) {}
friend Rat<T> operator*(Rat<T>&x,Rat<T>&y) //      ::operator*()
{
return Rat<T>(x.a*y.a,x.b*y.b);
}
private:
T a,b;
};