統計類別在執行期的實例數量:建構 +1、複製建構 +1、解構 -1。
class Counter {
static size_t count;
public:
Counter() { ++count; }
Counter(const Counter&) { ++count; }
~Counter() { --count; }
static size_t howMany() { return count; }
};
size_t Counter::count = 0;
缺點:所有使用此類的類別共享同一計數。
template
class Counter {
static size_t count;
public:
Counter() { ++count; }
Counter(const Counter&) { ++count; }
~Counter() { --count; }
static size_t howMany() { return count; }
};
template size_t Counter::count = 0; // 可置於標頭檔
class Widget {
Counter c;
public:
static size_t howMany() { return Counter::howMany(); }
};
howMany()
class Widget : public Counter {
// 直接繼承 howMany()
};
howMany()delete static_cast*>(new Widget) )
template
class Counter {
public:
Counter() { ++count; }
Counter(const Counter&) { ++count; }
protected:
~Counter() { --count; } // 禁止 delete base*
public:
static size_t howMany() { return count; }
private:
static size_t count;
};
現在 Counter → **編譯錯誤**,避免未定義行為。
class Widget : private Counter {
public:
using Counter::howMany; // 暴露靜態方法
};
Counter* p = new Widget; 隱性轉換
class SpecialWidget : public Widget, public Counter { };
SpecialWidget 計數正確 (自己的 Counter)Widget 計數**錯誤**:每建構一個 SpecialWidget,Widget 建構函數執行 → Counter +1Widget::howMany() = Widget 實例 + SpecialWidget 實例模板計數器無法正確區分繼承鏈中的基類與衍生類實例,因為基類建構函數在衍生類建構時必然執行。
template
class Registry {
static std::atomic count;
public:
static void add() { ++count; }
static void remove() { --count; }
static size_t howMany() { return count; }
};
// 使用者在每個建構/解構手動呼叫
class Widget {
public:
Widget() { Registry::add(); }
Widget(const Widget&) { Registry::add(); }
~Widget() { Registry::remove(); }
static size_t howMany() { return Registry::howMany(); }
};
優點:完全控制計數時機,可在衍生類決定是否呼叫基類登記。缺點:需手動維護,易忘。
| 方案 | 大小開銷 | 使用便利性 | 繼承鏈正確性 | 推薦場景 |
|---|---|---|---|---|
| 組合 | +1 byte | 需轉發 | 同繼承 | 單一類別、不介意大小 |
| public 繼承 + protected dtor | 0 (EBO) | 直接繼承 | 失效 | 單一類別、效能敏感 |
| private 繼承 + using | 0 (EBO) | 一行轉發 | 失效 | 單一類別、語意正確 |
| 外部登記表 | 0 | 手動呼叫 | 可控 | 複雜繼承體系 |