題目:用C++設計一個不能被繼承的類.
常規的解法:把構造函數設爲私有函數
咱們經過定義共有的靜態函數來建立和釋放類的實例。
class SealedClass1
{
public:
static SealedClass1* GetInstance()
{return new SealedClass1();}
static void DeleteInstance(SealedClass1* pInstance)
{delete pInstance;}
private:
SealedClass1(){}
~SealedClass1(){}
};
這個類是不能被繼承,但總以爲它和普通的類型有些不同,使用起來有點不方便.好比咱們只能獲得位於堆上的實例,而得不到位於棧上的實例。
新奇的解法:利用虛擬繼承,能給面試官留下很好的印象
template<typename T> class MakeSealed
{
friend T;
private:
MakeSealed() {}
~MakeSealed(){}
}
class SealedClass2: virtual public MakeSealed<SealedClass2>
{
public:
SealedClass2(){}
~SealedClass2(){}
};
這個SealedClass2使用起來和通常的類型沒有多大差異,咱們能夠在棧上、也能夠在堆上建立實例。儘管類MakeSealed<SealedClass2>的構造函數和析構函數都是私有的,
但因爲類SealedClass2是它的友元類型,所以在SealedClass2中調用MakeSealed<SealedClass2>的構造函數和析構函數都不會引發編譯錯誤.
但當咱們試圖從SealedClass2中繼承一個類並建立它的實例的時候,卻不可以經過編譯。好比當咱們從SealedClass2中繼承出類型Try:
class Try: public SealedClass2
{
public:
Try(){}
~Try(){}
};
因爲類SealedClass2是從類MakeSealed<SealedClass2>虛繼承過來的,在調用Try的構造函數的時候,會跳過SealedClass2而直接調用MakeSealed<SealedClass2>的構造函數.
很是遺憾的是Try不是MakeSealed<SealedClass2>的友元類型,所以不能調用它的私有構造函數.
經過上面的分析,咱們發現從SealedClass2繼承的類,一旦實例化就會致使編譯出錯,所以SealedClass2不能被繼承,這也就知足了題目的要求.