单例模式有许多种实现方法,在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. JAVAEE学习

    首先要明白Java体系设计到得三个方面:J2SE,J2EE,J2ME(KJAVA).J2SE,Java 2 Platform Standard Edition,我们经常说到的JDK,就主要指的这个,它 ...

  2. uploadify在asp.net中的试用小结

    花了差不多一下午的时间,总算把uploadify插件运行起来,在此对自己遇到的问题以及过程做一个小结. 一.使用步骤 1.在官网下载最新的插件包,并将包解压. 2.新建asp.net web项目,将解 ...

  3. JAVA泛型那些事儿

    本篇内容源于本人一个好友sgpro提供的java学习例子,现拿出来给大家分享. 此例子非常直观的通过代码讲解了java泛型的用法和好处,是笔者一直珍藏的最好的泛型学习笔记. 一.面向过程的时代 我们先 ...

  4. MySQL利用binlog来恢复数据库

    1.根据binlog解析出所有ring数据库的所有sql [mysql@localhost ]$ mysqlbinlog --no-defaults --database=ring --start-d ...

  5. JavaScript 客户端JavaScript之cookie和客户端持久性

    Document对象都有一个cookie属性,它使得JavaScript代码能够在用户的硬盘上持久地存储数据, 并且能够获取以这种方式存储的数据.客户端持久性是赋予WEB应用程序记忆力的一种简单方法. ...

  6. 你好,C++(28)用空间换时间 5.2 内联函数 5.3 重载函数

    5.2  内联函数 通过5.1节的学习我们知道,系统为了实现函数调用会做很多额外的幕后工作:保存现场.对参数进行赋值.恢复现场等等.如果函数在程序内被多次调用,且其本身比较短小,可以很快执行完毕,那么 ...

  7. image控件读取数据库二进制图片

    DataGridShowImage.aspx   <%@ Page language="c#" debug="true" Codebehind=" ...

  8. phpcms V9 联动菜单的调用

    /*********************************** 通过id获取显示联动菜单的 顶级父类的名称* @param  $linkageid 联动菜单id* @param  $keyi ...

  9. tcpdump使用和TCP/IP包分析

    关于tcpdump如何抓包,本文不再总结,可以查看 tcpdump的官方地址查看http://www.tcpdump.org 本文重点记录两个部分:           第一部分:tcpdump所抓包 ...

  10. php __clone实现

    <?php class Account { public $balance; public function __construct($balance) { $this->balance ...