用C++設計一個不能被繼承的類


在Java 中定義了關鍵字final,被final修飾的類不能被繼承。

首先想到的是在C++中,子類的構造函數會自動調用父類的構造函數。同樣,子類的析構函數也會自動調用父類的析構函數。要想一個類不能被繼承,只要把它的構造函數和析構函數都定義為私有函數。那么當一個類試圖從它那繼承的時候,必然會由於試圖調用構造函數、析構函數而導致編譯錯誤。

可是這個類的構造函數和析構函數都是私有函數了,怎樣才能得到該類的實例呢?可以通過定義靜態來創建和釋放類的實例。基於這個思路,可以寫出如下的代碼:

///////////////////////////////////////////////////////////////////////
// Define a class which can't be derived from
///////////////////////////////////////////////////////////////////////
class FinalClass1
{
public :
      static FinalClass1* GetInstance()
      {
            return new FinalClass1;
      }
 
      static void DeleteInstance( FinalClass1* pInstance)
      {
            delete pInstance;
            pInstance = 0;
      }
 
private :
      FinalClass1() {}
      ~FinalClass1() {}
};

這個類是不能被繼承,但在總覺得它和一般的類有些不一樣,使用起來也有點不方便。比如,只能得到位於堆上的實例,而得不到位於棧上實例。

能不能實現一個和一般類除了不能被繼承之外其他用法都一樣的類呢?辦法總是有的,不過需要一些技巧。請看如下代碼:

///////////////////////////////////////////////////////////////////////
// Define a class which can't be derived from
///////////////////////////////////////////////////////////////////////
template <typename T> 
class MakeFinal
{
      friend T;
 
private :
      MakeFinal() {}
      ~MakeFinal() {}
};
 
class FinalClass2 : virtual public MakeFinal<FinalClass2>
{
public :
      FinalClass2() {}
      ~FinalClass2() {}
};

這個類使用起來和一般的類沒有區別,可以在棧上、也可以在堆上創建實例。盡管類MakeFinal<FinalClass2>的構造函數和析構函數都是私有的,但由於類FinalClass2是它的友元函數,因此在FinalClass2中調用MakeFinal<FinalClass2>的構造函數和析構函數都不會造成編譯錯誤。

但當試圖從FinalClass2繼承一個類並創建它的實例時,卻不同通過編譯。

class Try : public FinalClass2
{
public :
      Try() {}
      ~Try() {}
};
 
Try temp; 

由於類FinalClass2是從類MakeFinal<FinalClass2>虛繼承過來的,在調用Try的構造函數的時候,會直接跳過FinalClass2而直接調用MakeFinal<FinalClass2>的構造函數。非常遺憾的是,Try不是MakeFinal<FinalClass2>的友元,因此不能調用其私有的構造函數。

基於上面的分析,試圖從FinalClass2繼承的類,一旦實例化,都會導致編譯錯誤,因此是FinalClass2不能被繼承。這就滿足了設計要求。

C++11中已經有了final關鍵字:它的作用是指定類的虛函數不能被該類的繼承類重寫(override),或者是指定一個類成為一個不能被繼承的類(final class)。

struct A
{
    virtual void foo() final;
};
 
struct B final : A
{
    void foo(); // Error: foo cannot be overridden as it's final in A
};
 
struct C : B // Error: B is final
{
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM