ProgrammingC++ 開発者

C++における「friend」とは何ですか?friend関数やクラスを使用することが推奨される場合と、これに伴うセキュリティや設計の微妙な点は何ですか?

Hintsage AIアシスタントで面接を突破

回答

キーワード friend は、特定の関数や他のクラスが、friendが宣言されたクラスのプライベートおよびプロテクトメンバーにアクセスできるようにします。friend関数はグローバルであったり、他のクラスのメソッドであったりすることができます。この構造により、クラスの内部状態にアクセスする必要がある関数を実装できますが、その関数は論理的にこのクラスのインターフェースとは関係ありません。

friendを使用することが推奨される場合:

  • 比較演算子や数学的演算子(operator<<, operator==など)を実装する際、関数が2つのオブジェクトのプライベートメンバーに同時にアクセスする必要があるとき。
  • 外部関数が論理的にはクラスのメソッドではないが、クラスの一部の挙動を実装する必要があるとき。
  • 一緒に働くクラスの緊密な結びつきのため(例えば、隣接する内部オブジェクトのプライベートデータへのアクセス)。

注意:

  • friend関数を追加することはプライベートデータへのアクセスを開放し、カプセル化を侵害します
  • friendの乱用は、コードの結合度の増加やセキュリティの低下を引き起こす可能性があります。

例:

class Box { int width; public: Box(int w): width(w) {} friend void printWidth(const Box &b); }; void printWidth(const Box &b) { std::cout << b.width << std::endl; }

ひねりのある質問

質問: friend関数は仮想関数にすることができますか?
よくある回答: はい、friendは関数の修飾子です。
正しい回答: いいえ、friend関数は仮想であることができません。なぜなら、彼らはクラスのメンバーではないからです!

例:

class Example { friend virtual void foo(); // コンパイルエラー: virtualはfriendに適用されません };

このトピックの微妙な点を知らないことによる実際のエラーの例


逸話: マトリックスライブラリの設計時に、すべての演算子をfriend関数にし、速度を向上させるために十分な状態を考慮せず、プライベートメンバーへのアクセスを不必要に開放しました。後に、プロジェクト内の他の関数がMatrixの内部状態を変更してしまう問題が発生しました。



逸話: コーポレートシステム内で、サポートクラスがプライベートメンバーへのアクセスを共有するためにfriendになりました。これにより循環依存が生じ、新しい機能の追加にはすべての関連クラスの変更が必要になりました。その後のリファクタリングには数週間かかりました。



逸話: プライベートテストのために、テストクラスをプロダクションクラスのfriendにすることにしました。ユニットテストのセットが複数出現した際に、実際に使用されるプライベートメソッドを追跡することが不可能になり、テストが内部実装に依存するようになり、コードの保守が難しくなりました。