C++フレンド関数とフレンドクラス:アクセス制御のマスター
C++フレンド関数とフレンドクラス:アクセス制御のマスター
このチュートリアルでは、C++でのフレンド関数とフレンドクラスの宣言と使用法を、明確な例で示します。
データ隠蔽はオブジェクト指向プログラミングの基盤であり、外部コードがクラスのprivateメンバに直接アクセスすることを防ぎます。protectedメンバは派生クラスからのみ可視で、外部からはアクセスできません。
以下の例を考えてみましょう:
class MyClass {
private:
int member1;
};
int main() {
MyClass obj;
// エラー!ここからprivateメンバにアクセスできない
obj.member1 = 5;
}
この制限にもかかわらず、C++にはフレンド関数という機構があり、通常のアクセス制御をバイパスしてクラスのprivateおよびprotectedデータを操作できます。
フレンドクラスも同様の概念で、クラス全体をフレンドとして振る舞わせます。両機能は慎重に使えば、カプセル化を損なうことなく柔軟性を高める強力なツールになります。
C++フレンド関数
フレンド関数は、クラスのprivateおよびprotectedメンバを読み書きできます。クラス定義内でfriendキーワードを使って宣言します。
class ClassName {
// ...
friend 戻り値の型 関数名(引数);
// ...
}
例1: 基本的なフレンド関数
// フレンド関数の動作を示すC++プログラム
#include <iostream>
using namespace std;
class Distance {
private:
int meter;
// フレンド関数
friend int addFive(Distance);
public:
Distance() : meter(0) {}
};
// フレンド関数の定義
int addFive(Distance d) {
// フレンド関数からprivateメンバにアクセス
d.meter += 5;
return d.meter;
}
int main() {
Distance D;
cout << "Distance: " << addFive(D);
return 0;
}
出力
Distance: 5
関数addFive()は、フレンド関数がprivateなmeterフィールドに自由にアクセスできることを示しています。この例はシンプルですが、フレンド関数の核心的な考え方を表しています。
例2: 2つのクラスを操作する
// フレンド関数を使って2つの異なるクラスのメンバを加算
#include <iostream>
using namespace std;
// 前方宣言
class ClassB;
class ClassA {
public:
// numAを12で初期化するコンストラクタ
ClassA() : numA(12) {}
private:
int numA;
// フレンド関数宣言
friend int add(ClassA, ClassB);
};
class ClassB {
public:
// numBを1で初期化するコンストラクタ
ClassB() : numB(1) {}
private:
int numB;
// フレンド関数宣言
friend int add(ClassA, ClassB);
};
// 両クラスのメンバにアクセス
int add(ClassA objectA, ClassB objectB) {
return (objectA.numA + objectB.numB);
}
int main() {
ClassA objectA;
ClassB objectB;
cout << "Sum: " << add(objectA, objectB);
return 0;
}
出力
Sum: 13
このプログラムでは、ClassAとClassBの両方が関数add()をフレンドとして宣言しています。これにより、この関数は両クラスのprivateデータにアクセスでき、numAとnumBの合計を求められます。
ClassAでのフレンド宣言がClassBの定義前にClassBを参照していることに注目してください。前方宣言class ClassB;がこの依存関係を解決します。
C++フレンドクラス
クラス全体をフレンドとして宣言すると、そのクラスのすべてのメンバ関数がホストクラスのprivateおよびprotectedメンバにアクセスできるようになります。構文はシンプルです:
class ClassB;
class ClassA {
// ClassBはClassAのフレンドクラス
friend class ClassB;
// ...
}
class ClassB {
// ...
}
ClassBがClassAのフレンドなので、ClassB内のあらゆるメソッドがClassAのprivateデータを自由に読み書きできます。逆は成り立ちません。ClassAがClassBをフレンドとして宣言しない限り、ClassAはClassBのprivateメンバにアクセスできません。
例3: フレンドクラスの実践
// フレンドクラスの動作を示すC++プログラム
#include <iostream>
using namespace std;
// 前方宣言
class ClassB;
class ClassA {
private:
int numA;
// フレンドクラス宣言
friend class ClassB;
public:
// numAを12で初期化するコンストラクタ
ClassA() : numA(12) {}
};
class ClassB {
private:
int numB;
public:
// numBを1で初期化するコンストラクタ
ClassB() : numB(1) {}
// ClassAのnumAとClassBのnumBを加算するメンバ関数
int add() {
ClassA objectA;
return objectA.numA + numB;
}
};
int main() {
ClassB objectB;
cout << "Sum: " << objectB.add();
return 0;
}
出力
Sum: 13
ClassBのadd()メソッドは、ClassAがClassBをフレンドとして宣言しているため、ClassAのprivateメンバnumAにアクセスできます。この例は、フレンドクラスがカプセル化を保ちながら密な協調を可能にすることを示しています。
全体として、フレンド関数とフレンドクラスは、クラス境界を越えた制御されたアクセスが必要な場合にC++で貴重なツールとなります。控えめに、設計上のメリットがある場合のみ使用してください。
C言語
- C# クラスとオブジェクト:堅牢な OOP の基礎
- C# 抽象クラスと抽象メソッドをマスターする:実践ガイド
- C# 部分クラスと部分メソッドを理解する
- C# sealed クラスとメソッドをマスターする:使用判断、実例、コードの安全性とパフォーマンス向上
- C++クラスとオブジェクト完全ガイド:オブジェクト指向プログラミングの実践
- C++ structとclassの違い:構文、特徴、使い分けのベストプラクティス
- C++ストレージクラス完全解説:スコープ、ライフタイム、使い方
- C++日付と時刻の完全ガイド:ctimeライブラリの活用
- C++オーバーロード完全マスター:関数と演算子のオーバーロード
- C++ポリモーフィズム完全理解:仮想関数と純粋仮想関数
- Javaオブジェクトとクラス:コアOOP概念を完全理解