OnTheWay2012
埋葬昨天的我,迎来重生的我!
posts - 15,  comments - 89,  trackbacks - 0

        以下的类实现了一些奇怪的功能,也可以说是一些不常用的功能;先不管这些功能到底是否有用,来看看这些类是怎么实现这些功能的也是挺有趣的。
(1)请设计一个只能在堆上生存的类
        在C++中对象有三个存储空间,静态存储区、堆、栈。请设计一个类,该类只能在堆上存储。如果你是第一次看到这种要求,请先别往下看,自己先想一想。想过了吗?是不是感觉实现这么个类有点困难?呵呵,其实这个问题如果换如下的问题的话可能更容易解答:请简单说明一下单例模式的实现方法?大家对单例模式一般都不太陌生吧,具体代码如下:

 

 

 1class CSingle
 2{
 3private:
 4    CSingle() 
 5    {
 6
 7    }

 8
 9    static CSingle *m_pSingle;
10
11public:
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
24CSingle *CSingle::m_pSingle = NULL;

        请注意在单例模式中的类CSingle的对象是不是都是在堆上的?是不是感觉好像知道怎么回答最初的问题了?
        实现只能在堆上生存的类的具体代码如下:

 1class COnlySurviveOnHeap
 2{
 3private:
 4 COnlySurviveOnHeap() 
 5 {
 6
 7 }

 8
 9 friend COnlySurviveOnHeap* GetInstance();
10}
;
11
12COnlySurviveOnHeap* GetInstance()
13{
14 return new COnlySurviveOnHeap;
15}

16
17

测试代码如下:

1int 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操作的方法来实现该类的设计呢?答案是当然可以了。
        具体代码如下:

 1class COnlySurviveOnStack
 2{
 3private:
 4 void* operator new(size_t) 
 5 {
 6  assert(false);
 7  return NULL;
 8 }

 9}
;
10

测试代码如下:

1int 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声明为友员.   代码如下:    

 1class CFinalClassMixin   
 2{   
 3friend class CParent;   
 4private:   
 5 CFinalClassMixin(){}   
 6 ~CFinalClassMixin(){}   
 7}
;   
 8 
 9class CParent : public CXXX   
10{   
11public:   
12 CParent(){}   
13 ~CParent(){}   
14}

15

它是从CXXX扩展的一个类(注,此时它还是能够被继承).现在我们需要它不能被继承.那么只要将代码改成    

 

1class CParent : public CFinalClassMixin,   public CXXX   
2{   
3public:   
4 CParent(){}   
5 ~CParent(){}   
6}
;  

       就行了.现在从CParent继承一个子类试试 。
      classCChild : public CParent { };    
      编译一下代码试试,发现:竟然没有作用!!!
      现在再回想一下我们这么操作的原因,也就是这个方案的原理:那就是让父类可以访问Mixin类的构造函数,但是子类不能访问。现在看看我们的代码,发现父类是CFinalClassMixin类的友员,可以访问它的构造函数。因为友员不能继承,所以CChild不能访问CFinalClassMixin的构造函数.所以应该不能被实例化。CChild的确不能访问CFinalClassMixin的构造函数,但是它却不必调用它!我想这就是问题的原因所在。CChild是通过CParent来构造CFinalClassMixin的,所以这个友员对他并没有什么用处! 现在问题找到了.要解决很简单.只要让CChild必须调用CFinalClassMixin的构造函数就行了,怎么才能达到目的呢? 还记得虚继承吗?虚继承的一个特征就是虚基类的构造函数由最终子类负责构造!所以将CParent从CFinalClassMixin继承改成从CFinalClassMixin虚继承就可以了.代码如下:  

 

1class CParent : virtual public   CFinalClassMixin, public CXXX   
2{   
3public:   
4 CParent(){}   
5 CParent(){}   
6}
;  

        现在试试,行了。但是可能有些人会对多继承心有余悸!但是我们这里并没有必要这么担心!为什么?因为我们的CFinalClassMixin类是纯的!pure!   也就是说它根本没有成员变量!那么我们就根本不用担心多继承带来的最大问题.菱形继承产生的数据冗余.以及二义性。现在还有个不足!那就是我们不能每次使用这个CFinalClassMixin类就在里面加上对某个类的友员声明啊!这多麻烦啊!   虽然不是什么大问题,但是我觉的还是要解决,因为我充分信任C++!解决的方法也很简单!那就是使用模板!具体描述就省略了,给出代码大家一看就知道了。
        下面是我得测试程序的完整代码(其中的CFinalClassmixin已经改成模板)。

 1template<class   T>   
 2class CFinalClassMixin   
 3{   
 4friend T;   
 5private:   
 6 CFinalClassMixin(){}   
 7 ~CFinalClassMixin(){}   
 8}
;  
 9 
10class CXXX   
11{   
12public:   
13 CXXX(){cout << "I am CXXX" << endl;}   
14 ~CXXX(){}   
15}
;  
16 
17class CParent : virtual public   CFinalClassMixin<CParent>public CXXX   
18{   
19public:   
20 CParent(){}   
21 ~CParent(){}   
22}
;  
23 
24class CChild : public CParent{};   
25int 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 阅读(1452) 评论(1)  编辑 收藏 引用 所属分类: C、C++

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理



<2010年5月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

常用链接

留言簿(4)

随笔分类

随笔档案

友情连接

搜索

  •  

最新评论

阅读排行榜

评论排行榜