この記事のポイント

  • 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;
};
@Reviewer
friendの乱用です。責務設計の整理で依存縮小を進めてください。

改善例

// 各責務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;
};
@Reviewer
friend依存設計は分割設計見直しを必須検討してください。

friendレビューの防止意義整理

防止崩壊 設計効果
カプセル化破壊 責務境界維持
責務混在化 SRP徹底
広域依存肥大 保守性向上
内部実装漏洩 API設計強化

観点チェックリスト


まとめ

レビューアーが毎回自問すべきは:

「このfriend指定は責務設計の敗北ではないか?」

  • friendは最小限の設計例外
  • 正当理由付けがレビュー文化の中核

「friend最小限レビュー」こそC++設計責務育成の基礎技術です。