单例模式有许多种实现方法,在c++中,甚至可以直接用一个全局变量做到这一点,但是这样的代码显得不优雅。使用全局对象能够保证方便地访问实例,但是不能保证只声明一个对象——也就是说除了一个全局实例外,仍然能创建相同类的本地实例。

定义一个单例类,使用类的私有静态指针变量指向类的唯一实例,并用一个公有的静态函数获取该实例。

定义:

class CSingleton

{

public:

staticCSingleton * GetInstance()

{

if(m_pInstance==NULL)

m_pInstance = new CSingleton();

return m_pInstance;

}

private:

CSingleton(){};

staticCSingleton *  m_pInstance;

};

用户访问唯一实例的函数只有GetInstance()成员函数。因为类的构造函数是私有的。GetInstance()的返回值是当这个函数第一次被调用时创建的实例。所以GetInstance()之后调用都返回同一个实例的指针。

单例类CSingleton的特征:

1.      CSingleton有一个指向唯一实例的静态指针m_pInstance,并且是私有的;

2.      CSingleton有一个公有的函数,可以获得这个唯一的实例,并且在需要的时候创建实例;

3.      CSingleton的构造函数是私有的,这样就不能从别处创建该类的实例。

但是该种实现单例类的方法有一个问题:m_pInstance指向的空间(实例)什么时候释放?

该实例的析构函数什么时候执行?

解决办法:让这个类自己知道在合适的时候把自己释放,或者把释放自己的操作让操作系统在某个适合时候执行。

在程序结束时,系统会自动析构所有的全局变量。事实上,系统也会析构该类的所有静态成员变量。利用这个特征,可以在单例类中定义一个内嵌类的静态成员变量,而这个内嵌类的唯一工作就是在析构函数中去释放单例类的实例。

在CSingleton类中定义一个CGarbo类的静态成员变量:

class  CSingleton

{

public:

static CSingleton * GetInstnace()

{

if(m_pInstance==NULL)

m_pInstance = newCSingleton();

return m_pInstance;

}

private:

CSingleton();

static CSingleton * m_pInstance;

class CGarbo

{

public:

~CGarbo()

{

if(CSingleton::m_pInstance)

delete  CSingleton::m_pInstance;

}

};

static CGarbo Garbo;

};

类CGarbo被定义为CSingleton的私有内嵌类,以防该类被在其他地方滥用。

程序运行结束时,系统会调用CSingleton的静态成员Garbo的析构函数,该析构函数会删除单例的唯一实例。

使用这种方法释放单例对象有以下特征:

在单例类内部定义专有的嵌套类;

在单例类内定义私有的专门用于释放的静态成员;

利用程序在结束时析构全局变量的特性,选择最终的释放时机;

使用单例的代码不需要任何操作,不必关心对象的释放。

另一种实现单例类的方法:定义单例类的实例为GetInstance函数的局部静态变量。

class CSingleton

{

public:

static  CSingleton &GetInstance()

{

static CSingleton  instance;

return  instance;

}

private:

CSingleton(){};

};

使用局部静态变量,非常强大的方法,完全实现了单例的特性,而且代码量更少,也不用担心单例销毁的问题。

但使用此种方法也会出现问题,当如下方法使用单例时问题来了,

Singletonsingleton = Singleton :: GetInstance();

这么做就出现了一个类拷贝的问题,这就违背了单例的特性。产生这个问题原因在于:编译器会为类生成一个默认的构造函数,来支持类的拷贝。

解决方法:禁止类拷贝和类赋值,禁止程序员用这种方式来使用单例

class  CSingleton

{

public:

static CSingleton &GetInstance()

{

static CSingleton instance;

return instance;

}

private:

CSingleton(){};

CSingleton(const CSingleton &){};

CSingleton & operate=(constCSingleton &){};

};

关于CSingleton(const Singleton&); 和 CSingleton & operate = (const Singleton&); 函数,需要声明成私用的,并且只声明不实现。这样就可以解决上边的问题,实现单例类。

c\c++复习基础要点08--c++单例模式的更多相关文章

  1. c/c++ 复习基础要点01-const指针、指针函数 函数指针、new/delete与malloc/free区别与联系

    1.      引用本身是有指针实现的:引用为只读指针 例子: int d=123; int& e=d;    //引用 int * const e=d; //只读指针,e指向d,不可修改e指 ...

  2. c++复习基础要点02 虚函数与模板 与static inline是否共存

    1.      虚函数能否定义为模板函数 当一个类有虚函数时,它一定有一个虚表,用来纪录每个虚函数的实际地址.这也就是说这个虚表的大小是在编译期就确定了的.有多少个虚函数,虚表就纪录几个.       ...

  3. c\c++复习基础要点16----枚举类型

    枚举类型: 语法格式: enum 枚举类型名 {变量值列表}; 例如: enum  Weekday{sun, mon, tue, wed, thu, fri, set}; 声明了枚举类型后,就可以定义 ...

  4. iOS系列 基础篇 08 文本与键盘

    iOS系列 基础篇 08 文本与键盘 目录: 1. 扯扯犊子 2. TextField 3. TextView 4. 键盘的打开和关闭 5. 打开/关闭键盘的通知 6. 键盘的种类 7. 最后再扯两句 ...

  5. CORS基础要点:关于dataType、contentType、withCredentials

    事实上,面试时我喜欢问跨域,因为多数开发者都知道它并且常用,而我希望能从面试者的回答中知道他在这个问题的深入程度,进一步看看面试者研究问题的思维方式及钻研精神,然而确实难到了很多人,当然这也不是面试通 ...

  6. 第二十七节:Java基础面向对象-静态,单例模式,继承详情知识点

    前言 Java基础面向对象-静态,单例模式,继承详情知识点.静态-static关键字,static变量,静态代码块,代码块(不加静态),对象创建过程,单例模式,继承. 静态-static关键字 // ...

  7. JUnit单元测试基础要点

    JUnit单元测试基础要点 1.JUnit是一种测试代码的框架,测试的目的是:保证代码没错,而不是保证代码正确. 2.测试类一般不要和目标类放在一起,但编译成的class文件是放在一起的. 3.单元测 ...

  8. JavaScript基础入门08

    目录 JavaScript 基础入门08 DOM 介绍 绑定事件 给一组元素绑定事件 节点 节点树 节点类型 选取文档内容 通过id选取元素 通过指定的标签名选取元素 用指定的css类来选取元素 通过 ...

  9. 068 01 Android 零基础入门 01 Java基础语法 08 Java方法 06 参数传递问题——基本数据类型传值

    068 01 Android 零基础入门 01 Java基础语法 08 Java方法 06 参数传递问题--基本数据类型传值 本文知识点:参数传递问题--基本数据类型传值 说明:因为时间紧张,本人写博 ...

随机推荐

  1. toString结果

    String[] str = new String[] { "a", "b", "c" }; System.out.println(str) ...

  2. mysql数据库编码

    MySQL数据库默认的编码是: character set :latin1 collation : latin1_swedish_ci 查看MySQL支持的编码: mysql> show cha ...

  3. C++小技巧之四舍五入与保留小数

    四舍五入:保留整数 int a = b+0.5; 保留一位小数  int a=(b+0.05)*10; double c=a/10; 保留二位小数  int a=(b+0.005)*100; doub ...

  4. 去掉eclipse上编辑时的提示

    用eclipse时,鼠标移到类上时会给出提示,如下图:

  5. java转换流

    转换流是把字节流转换成字符流,比如往一个文件中写内容,原本是一个字节一个字节的写,转换为字符流后,我们可以一个字符串,一个字符串的写,书写中文很方便 转换流class: OutputStreamWri ...

  6. 使用 ADD-ON SDK 开发 基于 Html JQuery 和 CSS 的 firefox 插件入门教程1: 创建一个简单的 Add-on

    [本文转载自http://sixpoint.me/942/implementing-simple-addon/] 实现一个简单的插件 教程的这个部分带你使用 SDK 来实现, 运行并打包一个插件. 这 ...

  7. javascript call()与apply()

    1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call ...

  8. spring事务分类简述

    spring事务的传播行为是面试中经常被问到的问题,要将事务的传播行为与隔离级别熟练的掌握,在实际开发过程中,特别是在并发高.更新数据量大.关系表比较多的情况下,经常会遇到关于事务的问题.首先,要了解 ...

  9. ServletContext对象的应用

    由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯.ServletContext对象通常也 ...

  10. Properties配置文件

    package file; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; ...