CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
山寨机中的战斗机! 程序优化工程师到底对IT界有没有贡献
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C++ 语言

私有析构函数的作用????

楼主ywchen2000(灌水大帝:努力奋斗)2006-07-13 18:56:28 在 C/C++ / C++ 语言 提问

私有析构函数的作用???? 问题点数:50、回复次数:24Top

1 楼lyskyly(浮生三笑)回复于 2006-07-13 19:16:44 得分 0

class   A  
  {  
  private:  
  ~A(){};  
  public:  
  void   Destory()  
  {delete   this;}  
  };  
   
  int   main()  
  {  
  A*   pa   =   new   A;  
  pa->Destory();  
  }  
  保证对象只能生成在堆上Top

2 楼lddLinan(不再五行中)回复于 2006-07-13 19:28:27 得分 0

用placement   new照样可以让他在栈上。  
  不过这样子是一定会出错的  
  void   Destory()  
  {delete   this;}//You   thought   that   it   must   be   on   heap  
   
  Top

3 楼lyskyly(浮生三笑)回复于 2006-07-13 19:37:04 得分 0

用placement   new照样可以让他在栈上  
  举个例子,不是太清楚:)  
  用placement   new让他在栈上,那也必须要有一个对象在栈上才行吧Top

4 楼UPCC(杂食动物)回复于 2006-07-13 19:42:34 得分 0

私有析构函数的作用????  
  -----------------------------  
  是“私有析构函数”,可不是“私有构造函数”  
   
  私有析构函数对对象好象影响不大,就算是public也是不能调用的啊。Top

5 楼triace_zhang(『雪梨码头』)回复于 2006-07-13 19:51:11 得分 0

用placement   new的确是可以创建在栈上。  
   
  class   A  
  {  
  private:  
  ~A(){};  
  int   n;  
  public:  
  void   Destory()  
  {delete   this;}  
  };  
   
   
  int   main()  
  {  
           
          const   int   num   =   sizeof(   A   );  
   
          char   ia[num];       //只要在栈上开辟足够空间就行  
          void   *d   =   ia;  
          cout   <<   d   <<   endl;  
           
          A   *pp   =   new   ((void*)ia)   A;    
          cout   <<   pp   <<   endl;  
                   
          system(   "pause"   );  
          return   1;  
  }  
   
  似乎只有private的构造函数有点用,析构不是很清楚。  
  Top

6 楼jixingzhong(瞌睡虫·星辰)回复于 2006-07-13 19:59:01 得分 0

构造函数   函数私有可以防止意外类型转换等非预期情况,  
  但是这个   析构私有   ...  
   
  有待研究   ...Top

7 楼lyskyly(浮生三笑)回复于 2006-07-13 19:59:26 得分 0

原来如此,学习了,那Scott   Meyers岂不是错了,它的  
  MC++上第27条用了这个技术Top

8 楼jixingzhong(瞌睡虫·星辰)回复于 2006-07-13 20:03:09 得分 0

想了想,  
  似乎这个没有任何的关系吧   ...  
   
  析构函数   不能被显示调用,  
  只能是自动调用,  
  那么是否   私有   都无所谓,  
  因为别人不会调用它   ......Top

9 楼lddLinan(不再五行中)回复于 2006-07-13 20:07:02 得分 0

析构函数   可以被显示调用,只有构造函数只有编译器才能显示调用Top

10 楼OOPhaisky(异化$渴望成功~~)回复于 2006-07-13 20:36:13 得分 0

用placement   new照样可以让他在栈上。  
  -------------------------------------  
  的确不错啊。  
   
  Top

11 楼zzw820626(偶要分,偶要星星)回复于 2006-07-13 21:02:55 得分 0

没见过Top

12 楼houdy(致力于图像/图形领域,成为有思想的程序员)回复于 2006-07-13 22:03:31 得分 0

我觉得私有析构函数可以防止类被实例化。例如某些policy类,mixin类,他们是对某些概念的抽象,根本就没有实例化的必要,而且它们通常作为基类(这种情况一般允许多个基类)。这时候将析构函数设置为私有的是有好处的。Top

13 楼lyskyly(浮生三笑)回复于 2006-07-13 22:16:55 得分 0

这种情况下该用protected,不然派生类也没法访问它的析构函数吧Top

14 楼fdimim(猿莫求愚√))回复于 2006-07-13 22:24:22 得分 0

markTop

15 楼sailing0123(梦想成真)回复于 2006-07-14 01:06:29 得分 0

“析构函数”是自动调用的,  
      为什么要那么麻烦!  
   
    “   防止类被实例化”?  
        我觉得这要看类本身是怎样设计的,  
        控制的好就不会出问题!!Top

16 楼cunsh(村少)回复于 2006-07-14 01:56:08 得分 0

markTop

17 楼corrupt(喜欢 睡在床板下 的思考)回复于 2006-07-14 08:34:10 得分 0

学习Top

18 楼paobo(吃螃蟹的鱼)回复于 2006-07-14 08:44:17 得分 0

认真学习  
  Top

19 楼sinall()回复于 2006-07-14 08:47:23 得分 25

《More   Effective   C++》  
   
  条款27:   要求或禁止基于堆的对象  
  有时你想这样管理某些对象,要让某种类型的对象能够自我销毁,也就是能够“delete   this”。很明显这种管理方式需要此类型对象被分配在堆中。而其它一些时候你想获得一种保障:“不在堆中分配对象,从而保证某种类型的类不会发生内存泄漏。”如果你在嵌入式系统上工作,就有可能遇到这种情况,发生在嵌入式系统上的内存泄漏是极其严重的,其堆空间是非常珍贵的。有没有可能编写出代码来要求或禁止在基于堆的对象(heap-based   object)呢?通常是可以的,不过这种代码也会把“在堆中”的概念搞得比你脑海中所想的要模糊。  
   
  要求基于堆的对象  
  让我们先从必须在堆中建立对象开始说起。为了执行这种限制,你必须找到一种方法禁止以调用“new”以外的其它手段建立对象。这很容易做到。非堆对象(non-heap   object)在定义它的地方被自动构造,在生存时间结束时自动被释放,所以只要禁止使用隐式的构造函数和析构函数,就可以实现这种限制。  
   
  把这些调用变得不合法的一种最直接的方法是把构造函数和析构函数声明为private。这样做副作用太大。没有理由让这两个函数都是private。最好让析构函数成为private,让构造函数成为public。处理过程与条款26相似,你可以引进一个专用的伪析构函数,用来访问真正的析构函数。客户端调用伪析构函数释放他们建立的对象。  
   
  例如,如果我们想仅仅在堆中建立代表无限精度数字的对象,可以这样做:  
   
  class   UPNumber   {  
  public:  
  UPNumber();  
  UPNumber(int   initValue);  
  UPNumber(double   initValue);  
  UPNumber(const   UPNumber&   rhs);  
   
  //   伪析构函数(一个const   成员函数,   因为  
  //   即使是const对象也能被释放)  
  void   destroy()   const   {   delete   this;   }  
  ...  
  private:  
  ~UPNumber();  
  };  
  然后客户端这样进行程序设计:  
   
  UPNumber   n; //   错误!(在这里合法,但是  
  //   当它的析构函数被隐式地  
  //   调用时,就不合法了)  
  UPNumber   *p   =   new   UPNumber; //   正确  
  ...  
  delete   p; //   错误!试图调用  
  //   private   析构函数  
  p->destroy(); //   正确  
  Top

20 楼bing_huo(我是一个演员!)回复于 2006-07-14 08:55:50 得分 0

保证对象只能在建立在堆上   并且此类不能被继承Top

21 楼CHANNEL5(鼠标肘,颈椎炎,肥胖,视力下降,腰间盘突出)回复于 2006-07-14 10:25:10 得分 0

似乎是为了导向错误,如果要使用堆(隐式或者显式),必须通过非常规的方法进行析构,而非一般化的DELETE或者自动调用析构,这样可以防止无意间使用基于堆的对象Top

22 楼fansgq()回复于 2006-07-14 10:44:23 得分 25

转贴:  
   
  四.禁止产生堆对象  
   
    上面已经提到,你决定禁止产生某种类型的堆对象,这时你可以自己创建一个资源封装类,该类对象只能在栈中产生,这样就能在异常的情况下自动释放封装的资源。  
   
    那么怎样禁止产生堆对象了?我们已经知道,产生堆对象的唯一方法是使用new操作,如果我们禁止使用new不就行了么。再进一步,new操作执行时会调用operator   new,而operator   new是可以重载的。方法有了,就是使new   operator   为private,为了对称,最好将operator   delete也重载为private。现在,你也许又有疑问了,难道创建栈对象不需要调用new吗?是的,不需要,因为创建栈对象不需要搜索内存,而是直接调整堆栈指针,将对象压栈,而operator   new的主要任务是搜索合适的堆内存,为堆对象分配空间,这在上面已经提到过了。好,让我们看看下面的示例代码:  
   
   
   
  #include   <stdlib.h>   //需要用到C式内存分配函数  
  class   Resource   ;   //代表需要被封装的资源类  
  class   NoHashObject  
  {  
   private:  
    Resource*   ptr   ;//指向被封装的资源  
    ...   ...   //其它数据成员  
    void*   operator   new(size_t   size)   //非严格实现,仅作示意之用  
    {  
     return   malloc(size)   ;  
    }  
    void   operator   delete(void*   pp)   //非严格实现,仅作示意之用  
    {  
     free(pp)   ;  
    }  
   public:  
    NoHashObject()  
    {  
     //此处可以获得需要封装的资源,并让ptr指针指向该资源  
     ptr   =   new   Resource()   ;  
    }  
    ~NoHashObject()  
    {  
     delete   ptr   ;   //释放封装的资源  
    }  
  };    
   
    NoHashObject现在就是一个禁止堆对象的类了,如果你写下如下代码:  
   
  NoHashObject*   fp   =   new   NoHashObject()   ;   //编译期错误!  
  delete   fp   ;    
   
    上面代码会产生编译期错误。好了,现在你已经知道了如何设计一个禁止堆对象的类了,你也许和我一样有这样的疑问,难道在类NoHashObject的定义不能改变的情况下,就一定不能产生该类型的堆对象了吗?不,还是有办法的,我称之为“暴力破解法”。C++是如此地强大,强大到你可以用它做你想做的任何事情。这里主要用到的是技巧是指针类型的强制转换。  
   
  void   main(void)  
  {  
   char*   temp   =   new   char[sizeof(NoHashObject)]   ;  
   
   //强制类型转换,现在ptr是一个指向NoHashObject对象的指针  
   NoHashObject*   obj_ptr   =   (NoHashObject*)temp   ;  
   
   temp   =   NULL   ;   //防止通过temp指针修改NoHashObject对象  
   
   //再一次强制类型转换,让rp指针指向堆中NoHashObject对象的ptr成员  
   Resource*   rp   =   (Resource*)obj_ptr   ;  
   
   //初始化obj_ptr指向的NoHashObject对象的ptr成员  
   rp   =   new   Resource()   ;  
   //现在可以通过使用obj_ptr指针使用堆中的NoHashObject对象成员了  
   ...   ...  
   
   delete   rp   ;//释放资源  
   temp   =   (char*)obj_ptr   ;  
   obj_ptr   =   NULL   ;//防止悬挂指针产生  
   delete   []   temp   ;//释放NoHashObject对象所占的堆空间。  
  }    
   
    上面的实现是麻烦的,而且这种实现方式几乎不会在实践中使用,但是我还是写出来路,因为理解它,对于我们理解C++内存对象是有好处的。对于上面的这么多强制类型转换,其最根本的是什么了?我们可以这样理解:  
   
    某块内存中的数据是不变的,而类型就是我们戴上的眼镜,当我们戴上一种眼镜后,我们就会用对应的类型来解释内存中的数据,这样不同的解释就得到了不同的信息。  
   
    所谓强制类型转换实际上就是换上另一副眼镜后再来看同样的那块内存数据。  
   
    另外要提醒的是,不同的编译器对对象的成员数据的布局安排可能是不一样的,比如,大多数编译器将NoHashObject的ptr指针成员安排在对象空间的头4个字节,这样才会保证下面这条语句的转换动作像我们预期的那样执行:  
   
  Resource*   rp   =   (Resource*)obj_ptr   ;    
   
    但是,并不一定所有的编译器都是如此。  
   
    既然我们可以禁止产生某种类型的堆对象,那么可以设计一个类,使之不能产生栈对象吗?当然可以。  
   
    五.禁止产生栈对象  
   
    前面已经提到了,创建栈对象时会移动栈顶指针以“挪出”适当大小的空间,然后在这个空间上直接调用对应的构造函数以形成一个栈对象,而当函数返回时,会调用其析构函数释放这个对象,然后再调整栈顶指针收回那块栈内存。在这个过程中是不需要operator   new/delete操作的,所以将operator   new/delete设置为private不能达到目的。当然从上面的叙述中,你也许已经想到了:将构造函数或析构函数设为私有的,这样系统就不能调用构造/析构函数了,当然就不能在栈中生成对象了。  
   
    这样的确可以,而且我也打算采用这种方案。但是在此之前,有一点需要考虑清楚,那就是,如果我们将构造函数设置为私有,那么我们也就不能用new来直接产生堆对象了,因为new在为对象分配空间后也会调用它的构造函数啊。所以,我打算只将析构函数设置为private。再进一步,将析构函数设为private除了会限制栈对象生成外,还有其它影响吗?是的,这还会限制继承。  
   
    如果一个类不打算作为基类,通常采用的方案就是将其析构函数声明为private。  
   
    为了限制栈对象,却不限制继承,我们可以将析构函数声明为protected,这样就两全其美了。如下代码所示:  
   
  class   NoStackObject  
  {  
   protected:  
    ~NoStackObject()   {   }  
   public:  
    void   destroy()  
    {  
     delete   this   ;//调用保护析构函数  
    }  
  };    
   
    接着,可以像这样使用NoStackObject类:  
   
  NoStackObject*   hash_ptr   =   new   NoStackObject()   ;  
  ...   ...   //对hash_ptr指向的对象进行操作  
  hash_ptr->destroy()   ;    
   
    呵呵,是不是觉得有点怪怪的,我们用new创建一个对象,却不是用delete去删除它,而是要用destroy方法。很显然,用户是不习惯这种怪异的使用方式的。所以,我决定将构造函数也设为private或protected。这又回到了上面曾试图避免的问题,即不用new,那么该用什么方式来生成一个对象了?我们可以用间接的办法完成,即让这个类提供一个static成员函数专门用于产生该类型的堆对象。(设计模式中的singleton模式就可以用这种方式实现。)让我们来看看:  
   
  class   NoStackObject  
  {  
   protected:  
    NoStackObject()   {   }  
    ~NoStackObject()   {   }  
   public:  
    static   NoStackObject*   creatInstance()  
    {  
     return   new   NoStackObject()   ;//调用保护的构造函数  
    }  
    void   destroy()  
    {  
     delete   this   ;//调用保护的析构函数  
    }  
  };    
   
    现在可以这样使用NoStackObject类了:  
   
  NoStackObject*   hash_ptr   =   NoStackObject::creatInstance()   ;  
  ...   ...   //对hash_ptr指向的对象进行操作  
  hash_ptr->destroy()   ;  
  hash_ptr   =   NULL   ;   //防止使用悬挂指针    
   
    现在感觉是不是好多了,生成对象和释放对象的操作一致了。  
  Top

23 楼gattso()回复于 2006-07-14 12:23:08 得分 0

markTop

24 楼superxiaomm(小美)回复于 2006-07-14 17:48:00 得分 0

释放你所开的堆空间,尤其是指针。对象消亡,只是他内部空间消亡,但是如果他里面在用指针开空间的话,那么如果是默认方式,只会把里面的指针地址给消亡,而对堆空间不做释放。所以要自己来放。Top

相关问题

关键词

得分解答快速导航

  • 帖主:ywchen2000
  • sinall
  • fansgq

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo