class Person { ... };
class Student : private Person { ... };
void eat(const Person& p);
Person p; Student s;
eat(p); // OK
eat(s); // 錯誤:Student 不能隱式轉換為 Person
私有繼承阻斷了向基類的隱式轉換,且繼承來的所有成員(無論原訪問級別)在派生類中均變為 private。
私有繼承意味著「根據……實現」。派生類關心的是基類的實現細節(如 protected 成員、虛函數),而非概念關係。這純屬實現技術,設計階段無語義。
復合同樣表達「is-implemented-in-terms-of」,且更易理解。原則:能用復合就用復合,只有必要時才用私有繼承。
必要場景:
protected 成員。virtual 函數。Widget 需重定義 Timer::onTick() 以統計使用情況,但 Widget 不是 Timer,故用私有繼承:
class Widget : private Timer {
private:
virtual void onTick() const; // 變為 private,防止客戶誤調用
};
替代方案:復合 + 嵌套類公開繼承 Timer:
class Widget {
private:
class WidgetTimer : public Timer {
public: virtual void onTick() const; ...
};
WidgetTimer timer;
};
後者更複雜,但能阻止 Widget 的派生類重定義 onTick,且可減少編譯依賴(僅需前置聲明)。
「空類」(無非靜態數據成員、無虛函數、無虛基類)獨立對象大小 ≥ 1,但作為基類子對象可佔 0 字節:
class Empty {};
class HoldsAnInt : private Empty { int x; };
sizeof(HoldsAnInt) == sizeof(int) // 典型編譯器均實現 EBO
EBO 通常僅在單繼承下有效,多重繼承時難以保證。對庫開發者(如 STL unary_function)有價值,但一般應用罕見。