C#和Java都提供了一種機制讓一個類不能被繼承,如C#中的sealed關鍵字和Java的final關鍵字,然而C++程序員就沒這麼好命了。不過C++也可以模擬出這種效果,原理基於:子類的構造函數會自動調用父類的構造函數,同理析構函數也是一樣。如果父類的構造函數和析構函數被設為私有的話,那麼子類就無法調用,也就達到了父類不可被繼承的目的了。原理很簡單,按此原理我也實作出一個自認為很實用的工具類,在此獻下丑,歡迎大家批評:
template< typename TDerive, typename TProvider >
class CFobidDeriveProviderBase
{
friend TDerive;
friend TProvider;
private:
CFobidDeriveProviderBase(){}
~CFobidDeriveProviderBase(){}
};
/*
* 提供禁止派生的功能,需要此功能的類可以從CFobidDeriveProvider派生,並將類名作為模板參數傳遞
*/
template< typename TDerive >
class CFobidDeriveProvider : virtual public CFobidDeriveProviderBase< TDerive, CFobidDeriveProvider<TDerive>>
{
public:
CFobidDeriveProvider(){}
~CFobidDeriveProvider(){}
};
/*
* 測試類,該類不可被繼承
*/
class CNoDerive : public CFobidDeriveProvider< CNoDerive >
{
public:
CNoDerive(){}
~CNoDerive(){}
void Alert()
{
AtlMessageBox( NULL, _T("Alert") );
}
};
之所以將繼承的結構分為2層:CFobidDeriveProvider和CFobidDeriveProviderBase,主要是方便使用,用戶只需直接從CFobidDeriveProvider派生就可實現一個不可被繼承的類,而不需要虛擬繼承。
若有類從CNoDerive派生:
class CSomeDerive : public CNoDerive
{
public:
CSomeDerive(){}
~CSomeDerive(){}
};
CSomeDerive的構造函數調用過程如下:由於CFobidDeriveProvider是從CFobidDeriveProviderBase虛擬派生,在虛繼承出現的繼承層次中,總是在構造非虛基類之前構造虛基類,因而會跳過CNoDerive和CFobidDeriveProvider的構造函數而直接調用CFobidDeriveProviderBase的構造函數,但CSomeDerive不是CFobidDeriveProviderBase的友元,因此也無法調用CFobidDeriveProviderBase的私有構造函數。故而編譯錯誤。