クラス内のprivateやprotectedメンバ変数は、
基本的に、同じクラス内のメンバ関数からしかアクセスできません。
しかし、フレンド機能を使うと、
通常の関数からもアクセスできるようになります。
フレンド機能には、フレンド関数とフレンドクラスがあります。
フレンド関数
フレンド関数は、メンバ関数ではない通常の関数から、
あるクラスのprivateやprotectedメンバ変数にアクセスしたい時に作成し、
関数内で、 あるクラスのprivateやprotectedメンバ変数にアクセスできます。
フレンド関数利用例
ファイル名:hito.h
class hito {
private:
int age;
friend void func(hito obj); // フレンド関数
friend void func(hito *obj); // フレンド関数(ポインタ版)
};
ファイル名:hito.cpp
#include "hito.h"
void func(hito obj) {
obj.age = 20; // privateメンバ変数にアクセス
}
void func(hito *obj) {
obj->age = 20; // privateメンバ変数にアクセス
// ポインタ版
}
ファイル名:main.cpp
#include "hito.h"
void main(void) {
hito satou;
func(satou);
hito suzuki;
func(&suzuki);
}
このプログラムでは、クラスhitoに対するフレンド関数を2つ作成し、
そのフレンド関数内からクラスhitoのprivateメンバ変数へアクセスする例です。
まず始めにフレンド関数の定義ですが、
フレンド関数は、クラスのメンバ関数ではありませんが、
クラス内に定義します。
この時、先頭にキーワードfriendを付けます。
フレンド関数に対するアクセス指定子(publicやprivate等)は無視されます。
フレンド関数の実体は、通常の関数と同じように記述します。
この時、キーワード:friendを付ける必要はありません。
このような記述をする事で、
クラスhitoとフレンド指定されたフレンド関数内で、
privateやprotectedメンバ変数にアクセスする事ができるようになります。
フレンド関数はメンバ関数ではなく、通常の関数なので、
thisポインタが渡されません。(thisポインタの説明はコチラ)
そのため、フレンド関数内で
privateやprotectedメンバ変数へアクセスするには、
フレンド関数の引数にクラス型を設定してフレンド関数内からアクセスするか、
グローバル領域にクラスのインスタンスを作成しておき、
フレンド関数内からアクセスするか。になります。
フレンドクラス
フレンドクラス利用例
/********** クラスhito1 **********/
class hito1 {
private:
int age;
public:
hito1(int age) {this->age = age; }
friend hito2; // フレンドクラス指定
};
/********** クラスhito2 **********/
class hito2 {
public:
void func1(hito1 obj);
void func2(hito1 obj);
};
void hito2::func1(hito1 obj) {
obj.age = 20; // privateメンバ変数にアクセス
}
void hito2::func1(hito1 obj) {
obj.age = 20; // privateメンバ変数にアクセス
}
/********** main関数 **********/
void main(void) {
hito1 satou(10);
hito2 suzuki;
suzuki.func1(satou); // フレンドクラスのメンバ関数呼び出し
suzuki.func2(satou); // フレンドクラスのメンバ関数呼び出し
}
この例では、クラスhito1の定義で、
クラスhito2をフレンドクラスに指定しています。
こうすることにより、クラスhito2の全てのメンバ関数は、
クラスhito1に対するフレンド関数となります。
クラスhito2のメンバ関数定義では、
キーワード:friendは必要ありません。
また、メンバ関数実体を記述する時は、
通常のフレンド関数とは異なり、
クラスのメンバ関数となるので、
スコープ解決演算子をつけて定義します。
さらに、クラスのメンバ関数なので、thisポインタが渡されます。
まとめると、フレンド指定するクラス側で、
フレンドクラスを指定だけすれば、
指定された側のクラスは通常通りのクラス記述をすれば良い事となり、
キレイな仕様となっています。