以下的類實現了一些奇怪的功能,也可以說是一些不常用的功能;先不管這些功能到底是否有用,來看看這些類是怎么實現這些功能的也是挺有趣的。
(1)請設計一個只能在堆上生存的類
在C++中對象有三個存儲空間,靜態存儲區、堆、棧。請設計一個類,該類只能在堆上存儲。如果你是第一次看到這種要求,請先別往下看,自己先想一想。想過了嗎?是不是感覺實現這么個類有點困難?呵呵,其實這個問題如果換如下的問題的話可能更容易解答:請簡單說明一下單例模式的實現方法?大家對單例模式一般都不太陌生吧,具體代碼如下:
1
class CSingle
2

{
3
private:
4
CSingle()
5
{
6
7
}
8
9
static CSingle *m_pSingle;
10
11
public:
12
static CSingle* GetInstance()
13
{
14
if (NULL == m_pSingle)
15
{
16
m_pSingle = new CSingle;
17
}
18
19
return m_pSingle;
20
}
21
22
};
23
24
CSingle *CSingle::m_pSingle = NULL;
請注意在單例模式中的類CSingle的對象是不是都是在堆上的?是不是感覺好像知道怎么回答最初的問題了?
實現只能在堆上生存的類的具體代碼如下:
1
class COnlySurviveOnHeap
2

{
3
private:
4
COnlySurviveOnHeap()
5
{
6
7
}
8
9
friend COnlySurviveOnHeap* GetInstance();
10
};
11
12
COnlySurviveOnHeap* GetInstance()
13

{
14
return new COnlySurviveOnHeap;
15
}
16
17
測試代碼如下:
1
int main(int argv, char *argc[])
2

{
3
COnlySurviveOnHeap *pOnlySurviveOnHeap = GetInstance();//right
4
COnlySurviveOnHeap object;//error
5
6
return 0;
7
}
8
是不是感覺很簡單?是不是感覺和單例模式很像?我在網上搜索了一下這個問題的解答,好多人把單例模式的代碼作為一種實現。但是單例模式的這種實現多了一個限制,那就是只能有一個對象,所以感覺不是太符合題意。
(2)請設計一個只能在棧上生存的類
什么樣的類對象是在堆上生存的呢?那就是通過new創建的對象(不考慮使用malloc分配內存后再調用inplace new的這種方式)。是否可以考慮禁止對這個類進行new操作的方法來實現該類的設計呢?答案是當然可以了。
具體代碼如下:
1
class COnlySurviveOnStack
2

{
3
private:
4
void* operator new(size_t)
5
{
6
assert(false);
7
return NULL;
8
}
9
};
10
測試代碼如下:
1
int main(int argv, char *argc[])
2

{
3
COnlySurviveOnStack *pOnlySurviveOnStack = new COnlySurviveOnStack;//error
4
COnlySurviveOnStack object;//right
5
6
return 0;
7
}
8
(3)請設計一個類該類不能夠作為基類
以下的內容是轉載的。向想出這種方法并且寫的這么詳細這么容易懂的大蝦致敬!我只修改了一下排版格式。
如果大家熟悉java的話應該知道java中有一種類不能被繼承,那就是final類.這種類有很多用處,尤其是在大的項目中控制類的繼承層次。
使子類數量不至于爆炸,在使用了多繼承的類層次中這也是防止出現菱形繼承層次結構的一個好辦法,要實現一個不能被繼承的類有很多方法。如何使類不能被繼承的主要的思路就是使子類不能構造父類的部分,這樣子類就沒有辦法實例化整個子類。這樣就限制了子類的繼承。所以我們可以將父類的構造函數聲明成為私有的,但是這樣父類不就不能實例化了嗎?可以添加一個靜態幫助函數來進行構造。雖然這樣很簡陋,但是這的確是一種解決方法。可是如果只有這個方法能夠解決,那么C++實在是太不靈活了.而且這也不值得寫一片文章出來!有沒有辦法解決上面的方法中的那些問題呢?
當然有!我們可以利用友員不能被繼承的特性!
首先假設已經有一個類CXX.這是某一個類層次的分支,我們現在要從CXX繼承一個Final子類CParent來,也就是CParent不能夠被繼承. 我們可以充分利用友員不能被繼承的特點,也就是說讓CParent是某一個類的友員和子類,CParent可以構造,但是CParent的子類CChild確不能繼承那個友員特性,所以不能被構造.所以我們引入一個CFinalClassMixin。
我們對這個類的功能是這么期望的:
任何類從它繼承都不能被實例化同時這個類本身我們也不希望它被實例化。
如何實現這個類那?很簡單!那就是實現一個構造函數和析構函數都是private的類就行了.同時在這類里面將我們的CParent聲明為友員. 代碼如下:
1
class CFinalClassMixin
2

{
3
friend class CParent;
4
private:
5
CFinalClassMixin()
{}
6
~CFinalClassMixin()
{}
7
};
8
9
class CParent : public CXXX
10

{
11
public:
12
CParent()
{}
13
~CParent()
{}
14
};
15
它是從CXXX擴展的一個類(注,此時它還是能夠被繼承).現在我們需要它不能被繼承.那么只要將代碼改成
1
class CParent : public CFinalClassMixin, public CXXX
2

{
3
public:
4
CParent()
{}
5
~CParent()
{}
6
};
就行了.現在從CParent繼承一個子類試試 。
classCChild : public CParent { };
編譯一下代碼試試,發現:竟然沒有作用!!!
現在再回想一下我們這么操作的原因,也就是這個方案的原理:那就是讓父類可以訪問Mixin類的構造函數,但是子類不能訪問。現在看看我們的代碼,發現父類是CFinalClassMixin類的友員,可以訪問它的構造函數。因為友員不能繼承,所以CChild不能訪問CFinalClassMixin的構造函數.所以應該不能被實例化。CChild的確不能訪問CFinalClassMixin的構造函數,但是它卻不必調用它!我想這就是問題的原因所在。CChild是通過CParent來構造CFinalClassMixin的,所以這個友員對他并沒有什么用處! 現在問題找到了.要解決很簡單.只要讓CChild必須調用CFinalClassMixin的構造函數就行了,怎么才能達到目的呢? 還記得虛繼承嗎?虛繼承的一個特征就是虛基類的構造函數由最終子類負責構造!所以將CParent從CFinalClassMixin繼承改成從CFinalClassMixin虛繼承就可以了.代碼如下:
1
class CParent : virtual public CFinalClassMixin, public CXXX
2

{
3
public:
4
CParent()
{}
5
CParent()
{}
6
};
現在試試,行了。但是可能有些人會對多繼承心有余悸!但是我們這里并沒有必要這么擔心!為什么?因為我們的CFinalClassMixin類是純的!pure! 也就是說它根本沒有成員變量!那么我們就根本不用擔心多繼承帶來的最大問題.菱形繼承產生的數據冗余.以及二義性。現在還有個不足!那就是我們不能每次使用這個CFinalClassMixin類就在里面加上對某個類的友員聲明啊!這多麻煩啊! 雖然不是什么大問題,但是我覺的還是要解決,因為我充分信任C++!解決的方法也很簡單!那就是使用模板!具體描述就省略了,給出代碼大家一看就知道了。
下面是我得測試程序的完整代碼(其中的CFinalClassmixin已經改成模板)。
1
template<class T>
2
class CFinalClassMixin
3

{
4
friend T;
5
private:
6
CFinalClassMixin()
{}
7
~CFinalClassMixin()
{}
8
};
9
10
class CXXX
11

{
12
public:
13
CXXX()
{cout << "I am CXXX" << endl;}
14
~CXXX()
{}
15
};
16
17
class CParent : virtual public CFinalClassMixin<CParent>, public CXXX
18

{
19
public:
20
CParent()
{}
21
~CParent()
{}
22
};
23
24
class CChild : public CParent
{};
25
int main(int argc, char* argv[])
26

{
27
CParent a; // 可以構造
28
//CChild b; //不能構造
29
return 0;
30
}
31
32
現在只要對不想被繼承的類加入一個CFinalClassMixin混合類做父類就行了。通過限制構造函數,我們就達到了限制繼承的目的。但是這對有些還是個例外,比如全是靜態函數的類.這些類本身就不需要構造。所以我們對它沒有辦法.但是在大多數情況下,一個全是靜態函數的類多少暗示了程序本身的設計可能是需要斟酌的其實這只是Mixin類(混合類)使用的一個小小例子.還有很多其他的用處,比如UnCopiale等等.就不多說了。我想說明的是大家可能對多繼承比較反感。但是過分否定也是得不償失的。現在對多繼承到底應不應該使用還處在爭論階段。我覺得一個方法是否使用得當,關鍵還是在于使用的人。
歡迎各位高手批評指正!
posted on 2010-05-20 19:38
OnTheWay 閱讀(1513)
評論(1) 編輯 收藏 引用 所屬分類:
C、C++