首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

C++ 實現不可繼承類的三種方案:從私有建構子到 C++11 final 關鍵字

     編輯:更多程式設計知識

Java 提供 final 關鍵字禁止類被繼承,C++ 雖無直接對應語法(C++11 前),卻可透過建構子存取控制、CRTP 機制或現代 final 關鍵字達成同樣目標。本文由淺入深解析三種主流實作,並對比其優缺點與適用場景。

方案一:私有建構子/解構子 + 靜態工廠方法

核心思想:將建構子與解構子宣告為 private,外部無法直接建構或銷毀物件,衍生類因無法呼叫基底類建構子而編譯失敗。提供 static 工廠方法控制物件生命週期:

class FinalClass1 {
public:
    static FinalClass1* GetInstance() { return new FinalClass1; }
    static void DeleteInstance(FinalClass1* p) { delete p; p = 0; }

private:
    FinalClass1() {}
    ~FinalClass1() {}
};

缺點:僅能動態配置於堆疊,無法建立堆疊物件;使用介面與一般類別差異大,需手動管理記憶體。

方案二:CRTP (Curiously Recurring Template Pattern) + 虛擬繼承

利用模板基底類別 MakeFinal<T> 將建構子/解構子設為 private,並宣告目標類別 T 為 friend。目標類別以 virtual public 繼承模板基底:

template <typename T>
class MakeFinal {
    friend T;
private:
    MakeFinal() {}
    ~MakeFinal() {}
};

class FinalClass2 : virtual public MakeFinal<FinalClass2> {
public:
    FinalClass2() {}
    ~FinalClass2() {}
};

原理:虛擬繼承導致最衍生類直接呼叫虛擬基底建構子。當嘗試繼承 FinalClass2 並實例化時,編譯器嘗試呼叫 MakeFinal<FinalClass2> 的私有建構子,因非友元而失敗:

class Try : public FinalClass2 {  // 編譯錯誤:無法存取 MakeFinal 私有建構子
public:
    Try() {}
    ~Try() {}
};
Try temp;  // 錯誤發生於此

優點:使用語法與一般類別完全一致,支援堆疊/堆疊配置,零額外執行期開銷。

方案三:C++11 final 關鍵字(現代標準做法)

C++11 引入 final 指定符,可修飾類別或虛擬函數:

struct A {
    virtual void foo() final;  // 禁止進一步覆寫
};

struct B final : A {           // 禁止被繼承
    void foo();  // Error: foo 在 A 中已標記 final
};

struct C : B { }  // Error: B 是 final 類別

優勢:語意明確、編譯器強制執行、無需樣板程式碼、與標準庫/第三方庫完美互操作。

選擇建議

場景推薦方案理由
C++11 或更新編譯器final 關鍵字標準、簡潔、零成本
舊標準 (C++98/03) 需支援堆疊物件CRTP + 虛擬繼承介面自然、效能最佳
舊標準且接受僅限堆疊配置私有建構子 + 工廠實作最簡單

掌握這三種技術,可根據專案編譯器限制與設計需求,靈活實現「不可繼承」語意。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved