C ++の友達を理解しようとしています。友だちを使う良いユースケースはいつですか?別のクラスが別のクラスの属性にアクセスできるようにしたいのであれば、それを単にパブリックとして作成するか、代わりにそのクラスから継承しないのですか?
ご協力ありがとうございました。
C ++の友達を理解しようとしています。友だちを使う良いユースケースはいつですか?別のクラスが別のクラスの属性にアクセスできるようにしたいのであれば、それを単にパブリックとして作成するか、代わりにそのクラスから継承しないのですか?
ご協力ありがとうございました。
回答:
クラスのメンバーを作成することは、すべてのユーザーにクラスへのアクセスをpublic
許可し、カプセル化を完全に解除することを意味します。
フレンドクラスがサブクラスではない場合、クラスからの継承は望ましくありません。クラスの内部にアクセスするためだけにサブクラス化することは、重大な設計ミスです。そして、サブクラスでさえ、そのベースクラスのプライベートメンバーを見ることができません。
の典型的な使用法はfriend
、ストリーム演算子などのメンバーにできない演算子の場合ですoperator+
。これらの場合、それらが関連付けられている実際のクラスは(常に)関数の最初のパラメーターではないため、関数はメンバーメソッドとして実装されます。
別の例は、コレクションのイテレータの実装です。イテレータ(イテレータのみ)は、親コレクションの内部を見る必要がありますが、コレクションのサブクラスではありません。
C ++で使用されるフレンドクラスを最もよく見た例は、単体テストです。単体テストは通常、内部についてすべてを知りたいが、あなたの一部ではないので、継承を試みても意味がありません。
単体テストの記述に慣れていない場合は、すぐに始めることをお勧めします。
この質問は、stackoverflowに関するものです。とにかく、クラスのプライベート部分を別のクラス(複数の場合もある)と共有したいが他の誰とも共有したくない場合にのみ、友達を使用します。あなたがそれらを公開すると、誰もがあなたの私的な部分を見ることができます プライバシーを強制する重要な制限が2つあります。1)友達を特定する必要があります。他の誰も友達にはなれません。2)フレンドクラスのサブクラスで「フレンドリ」な動作を継承できない
典型的な使用法は、クラスのインターフェースの一部を形成する関数へのアクセスを許可することですが、他のルールのおかげで、実際には適切なクラスの一部になることはできません。iostreamの挿入子/抽出子は、典型的な例です。
namespace whatever {
class something {
// ...
friend std::ostream &operator<<(std::ostream &os, something const &thing);
friend std::istream &operator>>(std::istream &is, something &thing);
};
}
これらのオペレーターをクラスのメンバーにしても機能しません。I / O操作は次のようになります。
whatever::something thing;
std::cout << thing;
メンバー関数として実装された演算子の場合、これは次のように解決されます。
std::cout.operator<<(thing);
つまり、関数はのメンバーでstd::cout
はなく、のメンバーである必要がありsomething
ます。std::ostream
常に変更したくないので、メンバー関数ではなくフリー関数で演算子をオーバーロードするのが唯一の合理的なオプションです。これにより、カプセル化を完全に無視してクラスのすべてをパブリックにするか、プライベートにして、本当に必要ないくつかのアクセスを許可するかの2つの可能性が残されます。
別のクラスを友達にすることはあまり一般的ではありません。この場合、通常はモジュールまたはサブシステムの順序で何かを作成します。これは、連携して動作し、世界全体に許可されていない、互いにある程度の特別なアクセス権を持つクラスのセットです。
C#のフレンドライクなクラスに対するこのリクエストには、それらを持たない言語であるフレンドクラスの必要性のかなり良い例があります。
ここで引用された卸売:
.NETのアクセス修飾子は、コードがどのように機能するかを同僚に信頼してもらい、バグを引き起こさないように設計されています。
しかし、この考えには欠陥があります。ソフトウェア開発は非常に複雑であるため、経験豊富なプログラマーは自分自身も信用しないことを知っています。このため、経験豊富なプログラマーは、設計上、偶発的な誤用で壊れないコードを書くことを好みます。.NETは、1つのクラスのみが関係する場合にこれを行うためのツールを提供しますが、プログラマーが2つまたは3つの相互作用するクラスの防弾セットを作成しようとした瞬間、これは失敗します。
これに対する.NETが意図するアプローチは、共有メンバーを「内部」としてマークすることです。これにより、クラスは相互の内部と対話できます。残念ながら、これにより、アセンブリ内の他のすべてのクラスが、偶然または意図的に、内部構造を混乱させることもできます。
C#Language PMのMads Torgersenはこの提案にさえ返信しており、懸念は確かに有効なものであると感じていますが、そこで提案されている特定の実装については不明であると述べています。
C ++ friend
は、説明されている問題に取り組む方法の1つにすぎません。
Javaでパッケージアクセスを使用した場合に、C ++のフレンドクラスが役立つことがわかりました。つまり、同じソースファイルに1つの単位として記述および維持されるほど密接に関連している一連のクラスがあります。それらの1つに取り組んでいる誰もが実際にそれらすべてに取り組んでいます。彼らが維持する不変量は、一緒に維持します。彼らがお互いの内部を見て、共有された不変量を維持できるようにすることは理にかなっています。
意味をなさないのは、保護されたアクセスです。私の内部の一部を公開するのが安全ではない場合、完全に無関係なプロジェクトで後で発生し、私のサブクラスであると主張するどんなジャッカナップにもそれを公開することは安全ではありません。他の人と同じように、サブクラスが私の公開インターフェースを使用できるようにします。(彼らが友達でない限り、しかしその場合私はそれらを書いて同じソースに実装したので、他のプロジェクトからはほとんど出てこない。)
プログラム内の2つの異なるクラスのプライベートまたは保護されたメンバーに対して操作を実行する必要がある外部関数があるとしましょう。ここで、その関数がアクセスしてこれらのクラスメンバーを実際に使用するためには、両方のクラスの友達にする必要があります。これらの両方のクラスの友達にすることで、それをクラスのメンバーにしないことは、これらのクラスのプライベートメンバーまたは保護されたメンバーを参照することになります。2つの異なるクラスのオブジェクトを操作する場合は、フレンド関数を使用する必要があると言えます。ただし、フレンド関数とクラスを使いすぎると、カプセル化の価値が低下する可能性があります。