フレンド関数とは
オブジェクト指向では意図しない操作を防ぐ為、データを隠蔽します。
それ故、privateを付けたクラスの非公開メンバは外部からのアクセスを遮断します。
しかし、非公開メンバに外部からアクセスする方法が用意されています。
この方法でアクセスの認められた外部関数をフレンド関数と呼びます。
データの隠蔽の重要性についてはオブジェクト指向とはで解説しています。
その為、基本的にはフレンド関数の使用は推奨されません。
しかし、やむを得ず必要な場合の為にこの機能が実装されています。
では、使い方を見てみましょう。
各クラスにフレンド関数を指定することができます。
フレンド関数に指定された外部関数はそのクラスのprivateメンバにアクセスすることができます。
フレンド関数の指定は、以下コードをクラス内に記述します。
friend 【戻り値の型】 【外部関数名】(【引数】);
クラスの定義内のどこに書いても構いません。
publicやprivateも関係ありません。
ここで指定した外部関数がフレンド関数と認められます。
関数そのものの記述については普通の関数と同様に行います。
宣言の際friendも必要ありません。
詳しくは関数を参照。
フレンド関数に指定する場合、指定元のクラスのメンバを参照する為、引数にそのクラスのインスタンスを持つことが殆どでしょう。
また、一つの関数を複数のクラスのフレンド関数とすることも出来ます。
フレンド関数と派生クラス
あるクラスのフレンド関数から、そのクラスの派生クラスのメンバを参照することが出来るでしょうか。
答えは出来ません。
フレンド関数に指定しているのは基本クラスなので、基本クラスに無いメンバを参照することは出来ません。
ただし、派生クラスのインスタンスから、基本クラスで定義したメンバにアクセスすることは可能です。
具体例を見てみましょう。
friend_class_sample1.c++
class B { int m; int n; friend int f(B b); } class D : public B { int n; } int f(B b);
基本クラスBをから派生クラスDを定義しました。
クラスBは関数f()をフレンド関数としています。
関数f()はクラスBのインスタンスを引数に持つ関数で、クラスBのメンバmとnを参照します。(処理は省略)
各クラスのメンバ変数はそれぞれ異なる値で初期化されるものとします。
コードでは省略していますが、B.m = 0、 B.n = 1、 D.n = 2としましょう。
この時、関数f()にクラスDのインスタンスを引数に与えた場合、mとnはどうなるでしょうか。
各クラスのメンバ変数はそれぞれ異なる値で初期化されるものとします。
まず、mは簡単ですね。
Dで上書きしていないので0になります。
しかし、nはどうでしょう。
こちらは1となります。
フレンド関数に登録したのはBなのでBの値が呼び出されます。
フレンドクラスとは
関数をフレンドと認めることが出来るなら、クラスでも出来そうですね。
フレンド関数と同様にクラスもフレンドクラスとして指定することが出来ます。
これを使えばあるクラスのメンバ関数を全てフレンドに指定する必要がなくなります。
記述方法は以下のようになります。
friend class 【クラス名】;
扱いは殆どフレンド関数と同様です。
フレンドクラスの派生クラス
フレンドクラスに指定したクラスの派生クラスはどうなるでしょうか。
こちらの場合も非公開メンバにはアクセスできません。
クラスAがクラスBをフレンドクラスに指定した場合、クラスBの派生クラスB'はAのメンバを扱えません。
ただし、クラスBのメンバ関数はAのメンバを参照できます。
その為、Bから派生したB'もそのメンバ関数を扱うことが出来ます。
正確に言うならば、派生クラスで新たに定義したメンバからは扱うことができません。