C++のfriend指定は必要性を説明し最小限に適用する|レビューでカプセル化破壊と設計責務を評価する技法
この記事のポイント
- friend指定の危険性と正当利用ケースを整理
- レビューでfriendの妥当性・最小化適用をどう評価するか解説
- 実務コード改善例・レビュー観点を提示
C++のfriendとは何をするものか
機能 | 説明 |
---|---|
friend関数 | 指定クラスのprivate/protectedにアクセス可能 |
friendクラス | 相互内部アクセス権付与 |
レビュー本質
friendは「責務境界を突破する例外指定」
なぜレビュー対象になるのか
① カプセル化破壊リスク
- privateを越えるアクセス権を乱発しやすい
② 設計責務が曖昧化
- 責務分離原則(SRP)が崩壊
③ API公開境界が不明確化
- 公開インターフェースがfriend側に依存
④ 保守時に影響範囲肥大化
- 内部構造が広域依存化
friend適用可否のレビュー原則
判定対象 | 設計判断 |
---|---|
出力系operator<< | 積極許容 |
内部ユーティリティヘルパ | 部分許容(設計理由説明要) |
相互アクセス制御 | 原則禁止 |
テスト用アクセス | 限定許容(UT専用化) |
汎用公開APIの代替 | 完全禁止 |
良い実装例:ストリーム出力
class User {
public:
User(int id, const std::string& name)
: id_(id), name_(name) {}
friend std::ostream& operator<<(std::ostream& os, const User& user);
private:
int id_;
std::string name_;
};
std::ostream& operator<<(std::ostream& os, const User& user) {
return os << "User{id=" << user.id_ << ", name=" << user.name_ << "}";
}
良い設計理由
- operator<<は出力責務
- 内部状態文字列化の自然実装
- カプセル化崩壊ではなく出力専用設計
レビュー観点
レビューアーは以下を確認する。
- friend指定の責務妥当性説明が可能か
- 公開API化で代替できないか
- ヘルパの責務境界整理が済んでいるか
- 相互friend相関が発生していないか
- テスト目的なら限定スコープ化されているか
良くない実装例: ケース1
class Account {
public:
friend class Transaction;
private:
int balance_;
};
@Reviewer相互アクセスをfriendで解決するのはSRP違反です。責務設計を整理してください。
改善例
class Account {
public:
int getBalance() const;
void applyTransaction(int delta);
};
ケース2: 内部更新ヘルパのfriend依存
class Order;
class OrderUpdater {
public:
void update(Order& o);
};
class Order {
friend class OrderUpdater;
private:
int quantity_;
};
@Reviewerヘルパをfriendにせず公開API経由で責務分離してください。
改善例
class Order {
public:
void setQuantity(int qty);
};
ケース3: 出力以外のオペレーターにfriend濫用
class Rectangle {
friend bool operator==(const Rectangle& a, const Rectangle& b);
private:
int width_;
int height_;
};
@Reviewer比較責務にfriendは不要です。public getter化検討してください。
改善例
bool operator==(const Rectangle& a, const Rectangle& b) {
return a.width() == b.width() && a.height() == b.height();
}
ケース4: テスト用friend無制限付与
class Service {
friend class ServiceTest;
};
@Reviewerテスト用friendはprivate実装に過剰依存しない設計整理を優先してください。
改善例
// API公開設計で極力friend不要な設計優先
ケース5: 複数ヘルパfriend連鎖
class User {
friend class UserRepository;
friend class UserCache;
friend class UserLogger;
};
@Reviewerfriendの乱用です。責務設計の整理で依存縮小を進めてください。
改善例
// 各責務APIをUser側に公開
class User {
public:
int id() const;
std::string name() const;
};
ケース6: ヘッダ肥大化誘発
// 全友達公開によりヘッダに大量friend記述
class ComplexModule {
friend class ModuleA;
friend class ModuleB;
friend class ModuleC;
};
@Reviewerfriend依存設計は分割設計見直しを必須検討してください。
friendレビューの防止意義整理
防止崩壊 | 設計効果 |
---|---|
カプセル化破壊 | 責務境界維持 |
責務混在化 | SRP徹底 |
広域依存肥大 | 保守性向上 |
内部実装漏洩 | API設計強化 |
観点チェックリスト
まとめ
レビューアーが毎回自問すべきは:
「このfriend指定は責務設計の敗北ではないか?」
- friendは最小限の設計例外
- 正当理由付けがレビュー文化の中核
「friend最小限レビュー」こそC++設計責務育成の基礎技術です。