(转载)http://www.blogjava.net/fhtdy2004/archive/2009/05/30/278971.html

很多情况下要求当前的程序中只有一个object。例如一个程序只有一个和数据库的连接,只有一个鼠标的object。通常我们都将构造函数的声明置于public区段,假如我们将
其放入private区段中会发生什么样的后果?这意味着什么?
      当我们在程序中声明一个对象时,编译器为调用构造函数(如果有的话),而这个调用将通常是外部的,也就是说它不属于class对象本身的调用,假如构造函数是私有的,
由于在class外部不允许访问私有成员,所以这将导致编译出错。
      然而,对于class本身,可以利用它的static公有成员,因为它们独立于class对象之外,不必产生对象也可以使用它们。
      此时因为构造函数被class私有化,所以我们要创建出对象,就必须能够访问到class的私有域;这一点只有class的成员可以做得到;但在我们建构出其对象之前,怎么能利用它
的成员呢?static公有成员,它是独立于class对象而存在的,“我们”可以访问得到。假如在某个static函数中创建了该class的对象,并以引用或者指针的形式将其返回(这里不
以对象返回,主要是构造函数是私有的,外部不能创建临时对象),就获得了这个对象的使用权。
      下面是例子:
class OnlyHeapClass
{
public:
   static OnlyHeapClass* GetInstance()
       {
              // 创建一个OnlyHeapClass对象并返回其指针
              return (new OnlyHeapClass);
       }
   void Destroy();
private:
       OnlyHeapClass() { }
       ~OnlyHeapClass() {}
};

int main()
{
       OnlyHeapClass *p = OnlyHeapClass::GetInstance();
       ... // 使用*p
       delete p;
       return 0;
}

这个例子使用了私有构造函数,GetInstance()作为OnlyHeapClass的静态成员函数来在内存中创建对象:由于要跨函数传递并且不能使用值传递方式,所以我们选择在堆上
创建对象,这样即使getInstance()退出,对象也不会随之释放,可以手动释放。
    
      构造函数私有化的类的设计保证了其他类不能从这个类派生或者创建类的实例,还有这样的用途:例如,实现这样一个class:它在内存中至多存在一个,或者指定数量个
的对象(可以在class的私有域中添加一个static类型的计数器,它的初值置为0,然后在GetInstance()中作些限制:每次调用它时先检查计数器的值是否已经达到对象个数的
上限值,如果是则产生错误,否则才new出新的对象,同时将计数器的值增1.最后,为了避免值复制时产生新的对象副本,除了将构造函数置为私有外,复制构造函数也要特别
声明并置为私有。
      如果将构造函数设计成Protected,也可以实现同样的目的,但是可以被继承。

另外如何保证只能在堆上new一个新的类对象呢?只需把析构函数定义为私有成员。
      原因是C++是一个静态绑定的语言。在编译过程中,所有的非虚函数调用都必须分析完成。即使是虚函数,也需检查可访问性。因些,当在栈上生成对象时,对象会自动析构,
也就说析构函数必须可以访问。而堆上生成对象,由于析构时机由程序员控制,所以不一定需要析构函数。保证了不能在栈上生成对象后,需要证明能在堆上生成它。这里OnlyHeapClass与一般对象唯一的区别在于它的析构函数为私有。delete操作会调用析构函数。所以不能编译。
       那么如何释放它呢?答案也很简单,提供一个成员函数,完成delete操作。在成员函数中,析构函数是可以访问的。当然detele操作也是可以编译通过。 
void OnlyHeapClass::Destroy() { 
        delete this; 

    构造函数私有化的类的设计可以保证只能用new命令在堆中来生成对象,只能动态的去创建对象,这样可以自由的控制对象的生命周期。但是,这样的类需要提供创建和撤销
的公共接口。
    另外重载delete,new为私有可以达到要求对象创建于栈上的目的,用placement new也可以创建在栈上。

---------------------------------------------------------------------------------------------------------------------------------
还是不懂啊:   
  1.为什么要自己调用呢?对象结束生存期时不就自动调用析构函数了吗?什么情况下需要自己调用析构函数呢?   
  ================================================================   
  比如这样一种情况,你希望在析构之前必须做一些事情,但是用你类的人并不知道,   
  那么你就可以重新写一个函数,里面把要做的事情全部做完了再调用析构函数。   
  这样人家只能调用你这个函数析构对象,从而保证了析构前一定会做你要求的动作。   
    
  2.什么情况下才用得着只生成堆对象呢?   
  ================================   
  堆对象就是new出来的,相对于栈对象而言。什么情况下要new,什么情况下在栈里面   
  提前分配,无非就是何时该用动态,何时该用静态生成的问题。这个要根据具体情况   
  具体分析。比如你在一个函数里面事先知道某个对象最多只可能10个,那么你就可以   
  定义这个对象的一个数组。10个元素,每个元素都是一个栈对象。如果你无法确定数   
  字,那么你就可以定义一个这个对象的指针,需要创建的时候就new出来,并且用list   
  或者vector管理起来。

---------------------------------------------------------------------------------------------------------------------------------
类中“私有”权限的含义就是:私有成员只能在类域内被访问,不能在类域外进行访问。   
    
  把析构函数定义为私有的,就阻止了用户在类域外对析构函数的使用。这表现在如下两个方面:   
    
  1.   禁止用户对此类型的变量进行定义,即禁止在栈内存空间内创建此类型的对象。要创建对象,只能用   new   在堆上进行。   
    
  2.   禁止用户在程序中使用   delete   删除此类型对象。对象的删除只能在类内实现,也就是说只有类的实现者才有可能实现对对象的   delete,用户不能随便删除对象。如果用户想删除对象的话,只能按照类的实现者提供的方法进行。   
    
  可见,这样做之后大大限制了用户对此类的使用。一般来说不要这样做;通常这样做是用来达到特殊的目的,比如在   singleton   的实现上。楼主可查找   singleton   的资料来了解它是怎么一回事。

(转载)C++中将构造函数或析构函数定义为private的更多相关文章

  1. C++中将构造函数或析构函数定义为private

    今天面试被问到了这个单例模式常用到的技术手段,下面进行分析: 很多情况下要求当前的程序中只有一个object.例如一个程序只有一个和数据库的连接,只有一个鼠标的object.通常我们都将构造函数的声明 ...

  2. C++中构造函数或析构函数定义为private

    转自:http://www.blogjava.net/fhtdy2004/archive/2009/05/30/278971.html 很多情况下要求当前的程序中只有一个object.例如一个程序只有 ...

  3. C++将类的构造函数、析构函数声明为private或者protected的用途

    如果将构造函数.析构函数声明为private或者protected,表示不能从类的外部正常调用构造和析构函数了. 这种用法的通常使用的场景如下: 1.如果不想让外面的用户直接构造一个类A的对象,而希望 ...

  4. (转载)C++中, 构造函数和析构函数能不能被显示调用?

    (转载)http://blog.csdn.net/zhangxinrun/article/details/6056321 代码: view plaincopy to clipboardprint?#i ...

  5. 定义类、System.Object对象、构造函数与析构函数、抽象类与静态类

    一.类定义 class MyClass { //类成员 } 1.访问级别 默认访问级别为internal(内部类),也可以是public(公共类) internal(内部类):当前项目中的代码才能访问 ...

  6. 虚基类——(1)定义人员类Person: 公有成员:姓名(Name); 保护成员:性别(Gender),年龄(Age); 构造函数和析构函数

    题目描述: (1)定义人员类Person: 公有成员:姓名(Name): 保护成员:性别(Gender),年龄(Age): 构造函数和析构函数 (2) 从人员类Person派生学生记录类Student ...

  7. C++的优秀特性3:构造函数和析构函数

    (转载请注明原创于潘多拉盒子) 构造函数和析构函数是C++中再熟悉不过的概念了,几乎每个了解一点C++的人都知道这两个概念是什么意思.一个对象的全部生命期中构造函数和析构函数执行的时机如下: 1. 为 ...

  8. C++学习之路—继承与派生(二):派生类的构造函数与析构函数

    (根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 由于基类的构造函数和析构函数是不能被继承的,所以 ...

  9. 拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友

     1.拷贝构造 //拷贝构造的规则,有两种方式实现初始化. //1.一个是通过在后面:a(x),b(y)的方式实现初始化. //2.另外一种初始化的方式是直接在构造方法里面实现初始化. 案比例如以 ...

随机推荐

  1. JavaScript高级程序设计(五): js的关键字instanceof和typeof使用

    JavaScript中instanceof和typeof 常用来判断一个变量是否为空,或者是什么类型的.但它们之间还是有区别的: 一.typeof 1.含义:typeof返回一个表达式的数据类型的字符 ...

  2. c编程:提示用户输入一个0—9的数字进行猜测电脑产生的随机数。一共有三次机会。

    // //  main.c //  使用c语言进行编程: 题目:由电脑生成一个由0-9之间的随机数,提示用户也输入一个数字进行猜测.当猜测三次仍不中的时候结束程序. 编译环境:Xcode6.3 特别介 ...

  3. Oracle 10g 默认安装带来的用户名/密码

    ORACLE数据库创建的时候,创建了一系列默认的用户和表空间 Oracle 10g 默认安装带来的用户名/密码 Username Password Description See Also CTXSY ...

  4. HDU 5351 MZL's Border (规律,大数)

    [HDU 5351 MZL's Border]题意 定义字符串$f_1=b,f_2=a,f_i=f_{i-1}f_{i-2}$. 对$f_n$的长度为$m$的前缀$s$, 求最大的$k$满足$s[1] ...

  5. (转)IOS学习笔记-2015-03-29 int、long、long long取值范围

    unsigned - - unsigned - - unsigned __int64的最大值: __int64的最小值:- unsigned __int64的最大值:  

  6. IOS 学习笔记 20150314

    Objective--C 类与对象 1 关键字 @interace 类定义 @end 类结束 @implementation 类实现 : 继承 @public 公用 @private 私有 @prot ...

  7. 基于NodeJs的网页爬虫的构建(一)

    好久没写博客了,这段时间已经忙成狗,半年时间就这么没了,必须得做一下总结否则白忙.接下去可能会有一系列的总结,都是关于定向爬虫(干了好几个月后才知道这个名词)的构建方法,实现平台是Node.JS. 背 ...

  8. imagecreatefromjpeg(): gd-jpeg, libjpeg: recoverable error: Corrupt JPEG data: 1 extraneous bytes be

    imagecreatefromjpeg(): gd-jpeg, libjpeg: recoverable error: Corrupt JPEG data: 1 extraneous bytes be ...

  9. mac 下 sublime text 运行c++/c 不能使用scanf/cin

    { "cmd": ["g++", "${file}", "-o", "${file_path}/${file_ ...

  10. 以前写过的ajax基础案例(王欢-huanhuan)

    //load方法的使用   $('#loadBtn').click(function(){    //responseTxt 包含来自请求的结果数据 //statusTxt 包含请求的状态(" ...