C++ 基底クラスのアクセス指定子

private 継承や protected 継承がよくわからないということをよく聞きます

クラスの継承というと is-a 関係だの is-implemented-in-terms-of 関係だのという言葉が出てきてしまうのが何となく難しそうに感じさせている一因だと思いますが、では本当に難しいことなのかというと実は別に難しくも何ともありません

private 継承や protected 継承がよくわからないということの原因はただ基底クラスのアクセス指定子が何を意味しているかを理解していないところにあるのだと思います
Fig.1

// public継承
class CDerivedClass1 : public CPublicBaseClass {
	...
};
// protected継承
class CDerivedClass2 : protected CProtectedBaseClass {
	...
};
// private継承
class CDerivedClass3 : private CPrivateBaseClass {
	...
};
// class で基底クラスのアクセス指定子を指定しないときは private継承
class CDerivedClass4 : CPrivateBaseClass {
	...
};
// struct で基底クラスのアクセス指定子を指定しないときは public継承
struct CDerivedClass5 : CPublicBaseClass {
	...
};

では基底クラスのアクセス指定子は一体何なのかというとこれが実に簡単なことで、ただ基底クラスの public メンバと protected メンバを派生クラスでどう扱うのかということを指定しているだけです

public な基底クラスの public メンバは 派生クラスの public メンバになり、private な基底クラスの public メンバは派生クラスの private メンバになり、そして protected な基底クラスの public メンバは派生クラスの protected メンバになります
また private な基底クラスの protected メンバは派生クラスの private メンバになり、protected な基底クラスと public な基底クラスの protected メンバは派生クラスの protected メンバになります
基底クラスの private なメンバは派生クラスには見えないのでクラスの派生/継承とは関係ありません

図にすればただこれだけのことです
Fig.2

さて、ここでまず private 継承ですが
上の図では private継承した基底クラスの public メンバも protected メンバもどちらも派生クラスの private メンバに割り振られていることが見て取れると思います
クラスの private メンバはそのクラス自身以外には誰にも見えないのですから、基底クラスをその private メンバに割り振る private 継承は純粋にその派生クラスの実装のためだけに存在しているということがわかると思います
Fig.3

では次に protected 継承です
protected継承では基底クラスの public メンバも protected メンバもどちらも派生クラスの protected メンバに割り振られています
protected メンバというものはそのクラスを継承した派生クラスの実装のためにあるものです
基底クラスをその protected メンバに割り振る protected 継承はその派生クラス自身が基底クラスとなって次の派生クラスのための実装を提供するという目的のために存在しているのです
クラス継承の影響がその派生クラス自身だけに留まらず、その派生クラスをさらに継承した次の派生クラスにも見えるという点が private 継承とは異なりますが、private 継承も protected 継承も派生クラスの実装のために存在しているというところは同じです
Fig.4

public 継承が実装のためというよりもむしろインターフェイスの継承という面が大きいところを思い出せば、public 継承と他の2つの継承を使い分ける点が正にそこにあるということもわかると思います
Fig.5

こういった前提を踏まえて、インターフェイスの継承を is-a 関係、実装の継承を is-implemented-in-terms-of 関係と言っているのです
分かってみると簡単なことじゃないですか?