首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 箴言:謹慎使用私有繼承

     編輯:關於C++

私有繼承不代表 is-a

class Person { ... };
class Student : private Person { ... };
void eat(const Person& p);
Person p; Student s;
eat(p); // OK
eat(s); // 錯誤:Student 不能隱式轉換為 Person

私有繼承阻斷了向基類的隱式轉換,且繼承來的所有成員(無論原訪問級別)在派生類中均變為 private。

含義:is-implemented-in-terms-of

私有繼承意味著「根據……實現」。派生類關心的是基類的實現細節(如 protected 成員、虛函數),而非概念關係。這純屬實現技術,設計階段無語義。

私有繼承 vs 復合

復合同樣表達「is-implemented-in-terms-of」,且更易理解。原則:能用復合就用復合,只有必要時才用私有繼承。

必要場景:

  1. 需要訪問基類的 protected 成員。
  2. 需要重定義基類的 virtual 函數。
  3. 空基優化(EBO)相關的極端空間優化需求。

案例:Timer 與 Widget

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,且可減少編譯依賴(僅需前置聲明)。

空基優化(EBO)

「空類」(無非靜態數據成員、無虛函數、無虛基類)獨立對象大小 ≥ 1,但作為基類子對象可佔 0 字節:

class Empty {};
class HoldsAnInt : private Empty { int x; };
sizeof(HoldsAnInt) == sizeof(int) // 典型編譯器均實現 EBO

EBO 通常僅在單繼承下有效,多重繼承時難以保證。對庫開發者(如 STL unary_function)有價值,但一般應用罕見。

總結

  • 私有繼承 = 實現細節復用,非接口繼承。
  • 優先選擇復合;僅在需訪問 protected/重定義 virtual 時考慮私有繼承。
  • EBO 是私有繼承的特有優勢,但適用場景極窄。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved