C++のアクセス修飾子は設計責務に沿って適切に選択する|レビューでカプセル化とAPI設計の整合性を確認する技法
この記事のポイント
- アクセス修飾子の設計原則を体系整理
- レビューで妥当性・責務境界をどう確認するか解説
- 実務コード改善例・レビュー観点を提示
C++におけるアクセス修飾子の基本構造
| 修飾子 | 意味 | 使用領域 |
|—|—|—|—|
| public
| 完全公開 | 外部API、利用者インターフェース |
| protected
| 継承者まで公開 | 継承設計時のみ利用 |
| private
| クラス内限定 | 内部状態・実装詳細 |
レビュー観点の本質
「責務の境界を誰にまで公開するのか?」
なぜレビュー対象になるのか
① カプセル化破壊を誘発しやすい
- 過剰なpublic公開
② 継承設計不整合が生じやすい
- protectedの安易乱用
③ 内部実装が外部依存に晒されやすい
- メンバー変数のpublic化
④ 保守性が崩壊しやすい
- 外部影響範囲の肥大化
アクセス修飾子レビュー原則
判定対象 | 設計判断 |
---|---|
public | 利用者が呼び出す必要がある最小範囲のみ |
protected | 継承戦略が明確なときのみ許可 |
private | 原則デフォルト |
良い実装例
class User {
public:
User(int id, const std::string& name)
: id_(id), name_(name) {}
int id() const { return id_; }
std::string name() const { return name_; }
private:
int id_;
std::string name_;
};
良い設計理由
- 外部利用はgetter提供のみ
- 内部状態は完全カプセル化
- public範囲が明示的で読み取りやすい
レビュー観点
レビューアーは以下を確認する。
- publicは利用者インターフェース最小限になっているか
- protectedの乱用が無いか(継承責務の正当性確認)
- privateがデフォルトで採用されているか
- 実装詳細がpublic化されていないか
- API利用者と実装保守者の責務境界が整理されているか
良くない実装例: ケース1
class User {
public:
int id_;
std::string name_;
};
@Reviewerメンバー変数のpublic公開は禁止です。アクセサ提供に整理してください。
改善例
private:
int id_;
std::string name_;
public:
int id() const;
std::string name() const;
ケース2: protectedの安易な乱用
class Base {
protected:
int internal_;
};
@Reviewer継承戦略が曖昧ならprotected公開は避けてください。内部状態隠蔽が原則です。
改善例
private:
int internal_;
public:
void setInternal(int val);
int getInternal() const;
ケース3: 実装詳細のAPI化
class Cache {
public:
std::unordered_map<std::string, std::string> data_;
};
@Reviewer内部実装型をpublic化せず専用API提供に整理してください。
改善例
private:
std::unordered_map<std::string, std::string> data_;
public:
void put(const std::string& key, const std::string& value);
std::string get(const std::string& key) const;
ケース4: 継承前提の不安定protected
class Shape {
protected:
int id_;
};
@Reviewer継承利用方針を明確に設計説明できる時のみprotectedを許可します。
改善例
class Shape {
private:
int id_;
protected:
Shape(int id); // 初期化専用責務に限定
};
ケース5: getter/setterの無思考大量公開
class Config {
public:
int getA() const;
void setA(int);
int getB() const;
void setB(int);
int getC() const;
void setC(int);
};
@Reviewer設定責務全体でまとめたAPI設計整理を優先検討してください。
改善例
class Config {
public:
void applySettings(const Settings&);
};
ケース6: モジュール間friend代替public
class Core {
public:
friend class ModuleA;
friend class ModuleB;
};
@Reviewerfriend代替でpublic化する設計はカプセル化破壊です。責務再整理してください。
改善例
Coreは必要最小限APIだけをpublic公開
アクセス修飾子レビューの実務意義
防止崩壊 | 設計効果 |
---|---|
カプセル化崩壊 | 実装詳細封鎖 |
保守不能化 | API境界安定化 |
継承爆発 | 責務整理 |
外部依存肥大 | 影響範囲制御 |
観点チェックリスト
まとめ
レビューアーが自問すべき本質はこれです:
「本当に外部からこの責務が見えて良いのか?」
- public公開はAPI設計の約束
- protected公開は設計責任を要説明
「カプセル化境界レビュー」こそC++設計育成の基本技法です。