如何保证只能在堆(heap)上创建对象?

代码:
  1. class OnlyHeapClass  
  2. {  
  3. public:  
  4.     OnlyHeapClass()  
  5.     {  
  6.     }  
  7.   
  8.     void Destroy()  
  9.     {  
  10.         delete this// 等效于"OnlyHeapClass::~OnlyHeapClass();", 写  
  11.                      // 成"OnlyHeapClass::~OnlyHeapClass();"更容易理  
  12.                      // 解public成员函数调用private析构函数.  
  13.     }  
  14.   
  15. private:  
  16.     ~OnlyHeapClass()  
  17.     {  
  18.     }  
  19. };  
  20.   
  21. int main()  
  22. {  
  23.     OnlyHeapClass *pInst = new OnlyHeapClass;  
  24.   
  25.     pInst ->Destroy(); // 如果类中没有定义Destroy()函数, 而在这里用"delete pInst;"代  
  26.                        // 替"pInst->Destroy();", 则会报错. 因为"delete pInst;"会去调  
  27.                        // 用类的析构函数, 而在类域外调用类的private成员函数必然会报错.  
  28.   
  29.     return 0;  
  30. }  
总结:  把析构函数定义为private访问权限, 就可以保证只能在堆(heap)上创建(new)一个新的类对象.
    
    原因是C++是一个静态绑定的语言. 在编译过程中, 所有的非虚函数调用都必须分析完成. 即使是虚函数, 也需检查可访问性. 因些, 当在栈(stack)上生成对象时, 对象会自动析构, 也就说析构函数必须可以访问. 而堆上生成对象, 由于析构时机由程序员控制, 所以不一定需要析构函数. 保证了不能在栈上生成对象后, 需要证明能在堆上生成它. 这里OnlyHeapClass与一般对象唯一的区别在于它的析构函数为私有, delete操作会调用析构函数, 所以不能编译.

    那么如何释放它呢? 答案也很简单, 提供一个成员函数, 完成delete操作. 在成员函数中, 析构函数是可以访问的, 当然detele操作也是可以编译通过.
  1. void OnlyHeapClass::Destroy()   
  2. {   
  3.     delete this;   
  4. }   

 

    析构函数私有化的类的设计可以保证只能用new命令在堆(heap)中创建对象, 只能动态的去创建对象, 这样可以自由的控制对象的生命周期. 但是, 这样的类需要提供创建和撤销的公共接口. 

    另外重载delete, new为私有可以达到要求对象创建于栈上的目的, 用placement new也可以创建在栈上.

 

  1. / 下面灰色字体系转载帮助理解之用 /  

 

 
四.禁止产生堆对象
    上面已经提到, 你决定禁止产生某种类型的堆对象, 这时你可以自己创建一个资源封装类, 该类对象只能在栈中产生, 这样就能在异常的情况下自动释放封装的资源.
    那么怎样禁止产生堆对象了? 我们已经知道, 产生堆对象的唯一方法是使用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++是如此地强大, 强大到你可以用它做你想做的任何事情. 这里主要用到的是技巧是指针类型的强制转换.    
    
  int main()   
  {   
   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()   ;   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值