一,題目
用C++設計一個不能被繼承的類。
二,分析
在Java中定義了關鍵字final,被final修飾的類不能被繼承。但在C++中沒有final這個關鍵字。
首先想到的是在C++
中,子類的建構函式會自動調用父類的建構函式。同樣,子類的解構函式也會自動調用父類的解構函式。要想一個類不能被繼承,我們只要把它的建構函式和解構函式都定義為私人函數。那麼當一個類試圖從它那繼承的時候,必然會由於試圖調用建構函式、解構函式而導致編譯錯誤。
可是這個類的建構函式和解構函式都是私人函數了,我們怎樣才能得到該類的執行個體呢?
通過定義靜態來建立和釋放類的執行個體。
三,實現
下面是一個單利模式的實現
#include <iostream> using namespace std; class Singleton {private: Singleton(); ~Singleton();// {} static Singleton *instance; public: static Singleton* GetInstance() { if(instance == NULL) { instance = new Singleton(); } return instance; } static void DeleteInstance() { if(instance != NULL) { delete instance; } }};Singleton* Singleton::instance=NULL;//一定要初始化(由於不能在方法體內部初始化,所以就放到外部)int main(){}
這個類是不能被繼承,但在總覺得它和一般的類有些不一樣,使用起來也有點不方便。比如,我們只能得到位於堆上的執行個體,而得不到位於棧上執行個體。
能不能實現一個和一般類除了不能被繼承之外其他用法都一樣的類呢?辦法總是有的,不過需要一些技巧。請看如下代碼:
class MakeFinal{ friend FinalClass2;private: MakeFinal() {} ~MakeFinal() {}};class FinalClass2 : virtual public MakeFinal{public: FinalClass2() {} ~FinalClass2() {}};
這個類使用起來和一般的類沒有區別,可以在棧上、也可以在堆上建立執行個體。儘管類MakeFinal的建構函式和解構函式都是私人的,但由於類FinalClass2是它的友元函數,因此在FinalClass2中調用MakeFinal<FinalClass2>的建構函式和解構函式都不會造成編譯錯誤。
但當我們試圖從FinalClass2繼承一個類並建立它的執行個體時,卻不同通過編譯。
class Try : public FinalClass2
{
public:
Try() {}
~Try() {}
};
Try temp;
由於類FinalClass2是從類MakeFinal
虛繼承過來的,在調用Try的建構函式的時候,會直接跳過FinalClass2而直接調用MakeFinal的建構函式。非常遺憾的是,Try不是MakeFinal的友元,因此不能調用其私人的建構函式。
基於上面的分析,試圖從FinalClass2繼承的類,一旦執行個體化,都會導致編譯錯誤,因此是FinalClass2不能被繼承。這就滿足了我們設計要求。