单例模式(Singleton Pattern)是设计模式中的一种,它用来保证系统中最多只能存在一个它的实例,其做法是由类自身来创建和持有它的对象实例,把对实例的创建权和管理权都控制在自己手中,以便控制实例数目。

关于如何在C++中实现单例模式的讨论已经太多了,我只是简单介绍一下可以继承的单例类。

首先介绍一下通常所见的单例类的写法,不妨设这个类叫做Singleton。

Singleton.h:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef _SINGLETON_H_
#define _SINGLETON_H_ #include <memory> class Singleton
{
public:
static Singleton& GetInstance(); private:
Singleton();
~Singleton(); // Use auto_ptr to make sure that the allocated memory for instance
// will be released when program exits (after main() ends).
static std::auto_ptr<Singleton> s_instance;
friend class std::auto_ptr<Singleton>; Singleton(const Singleton&);
Singleton& operator =(const Singleton&);
}; #endif

Singleton.cpp:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "Singleton.h"
#include <iostream>
#include <boost/thread.hpp> using namespace std;
using namespace boost; auto_ptr<Singleton> Singleton::s_instance; Singleton::Singleton()
{
cout << "Construct Singleton" << endl;
} Singleton::~Singleton()
{
cout << "Destruct Singleton" << endl;
} Singleton& Singleton::GetInstance()
{
static mutex s_mutex;
if (s_instance.get() == NULL)
{
mutex::scoped_lock lock(s_mutex);
if (s_instance.get() == NULL)
{
s_instance.reset(new Singleton());
}
// 'lock' will be destructed now. 's_mutex' will be unlocked.
}
return *s_instance;
}

这个类写的也不完美啦,比如双重判定也会有失效的时候,不过凑合用吧,哈哈。不过话说boost库里也有singleton,我为什么要自己写个呢,无奈地飘过。

废话不多说了,上面的单例类基本上解决了多线程安全问题、实例内存自动释放问题,算是一段可以使用的程序。不过如果系统中有大量单例类(这时候也得好好考虑一下design有没有问题),每个都要这么写一番岂不是很麻烦?要是可以写一个单例基类,以后再创造单例类的时候直接继承一下多方便啊。不过很明显的问题就在那个static对象指针,这个用来保存唯一实例的静态变量如果定义在基类里面,那所有的子类都只能用这同一个变量来保存它们各自的实例了,社会主义国家总得让每个子类都过上温饱生活吧!

以前的时候我还真不知道该怎么解决这个问题,但05年用了WTL(Windows Template Library)之后,我才意识到模板类可以帮助我(话说我真的是自己想到的,虽然现在搜一下能搜到一大堆)。这里要用的还不是普通的模板类,而是像ATL、WTL里面那样把要定义的类自身放入模板参数中,形如class MyClass : public Base<MyClass> { };。这样做有很多优点啦,最显著的比如不需要虚表(节省内存哦)、多态函数的调用在编译时就确定了(既加快了运行速度,也有利于编译器对代码进行优化)。

不妨把这个单例基类叫做ISingleton吧,看起来好像是个interface呢。代码如下:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#ifndef _ISingleton_H_
#define _ISingleton_H_ #include <memory>
#include <boost/thread.hpp> template <typename T>
class ISingleton
{
public:
static T& GetInstance()
{
static boost::mutex s_mutex;
if (s_instance.get() == NULL)
{
boost::mutex::scoped_lock lock(s_mutex);
if (s_instance.get() == NULL)
{
s_instance.reset(new T());
}
// 'lock' will be destructed now. 's_mutex' will be unlocked.
}
return *s_instance;
} protected:
ISingleton() { }
~ISingleton() { } // Use auto_ptr to make sure that the allocated memory for instance
// will be released when program exits (after main() ends).
static std::auto_ptr<T> s_instance; private:
ISingleton(const Singleton&);
ISingleton& operator =(const ISingleton&);
}; template <typename T>
std::auto_ptr<T> ISingleton<T>::s_instance; #endif

要利用ISingleton创建一个自己的单例类,比如MySingleton,可以使用如下的代码:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "Singleton.h"
#include "ISingleton.h"
#include <iostream> using namespace std; class MySingleton : public ISingleton<MySingleton>
{
public:
// blah blah private:
MySingleton()
{
cout << "Construct MySingleton" << endl;
} ~MySingleton()
{
cout << "Destruct MySingleton" << endl;
} friend ISingleton<MySingleton>;
friend class auto_ptr<MySingleton>; MySingleton(const MySingleton&);
MySingleton& operator =(const MySingleton&);
};

最最重要的,千万不要忘了把MySingleton的构造和析构函数弄成private的,还要添加两个友元。有人说ISingleton和MySingleton的析构函数都要加virtual,我倒是觉得没有必要呢,你说呢?另外要注意,MySingleton不能被继承哦。

可以继承的C++ Singleton基类的更多相关文章

  1. 【转载】 C++多继承中重写不同基类中相同原型的虚函数

    本篇随笔为转载,原文地址:C++多继承中重写不同基类中相同原型的虚函数. 在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数.下面就是一个例子: class CBaseA { public: ...

  2. 自定义继承于Page的基类

    自定义继承于Page的基类:MyBasePage[校验用户是否登录,如果登录则获取用户信息,否则跳转到登录页面]============================================ ...

  3. C++ 类的继承六(多继承的二义性--虚基类)

    //多继承的二义性--虚基类(了解为主) #include<iostream> using namespace std; /* 多继承在现在的项目开发中一般不使用,他会增加项目的复杂度 * ...

  4. C++可继承的单例基类模板

    目录 一.介绍 二.代码 三.关键处 五.参考资料 一.介绍 最近在写一个项目,其中用到好几个单例,类本身的设计不是很复杂,但是如果每个都写一遍单例又觉得有点冗余:所以查资料写了一个单例基类模板,只要 ...

  5. PythonI/O进阶学习笔记_3.2面向对象编程_python的继承(多继承/super/MRO/抽象基类/mixin模式)

    前言: 本篇相关内容分为3篇多态.继承.封装,这篇为第二篇 继承. 本篇内容围绕 python基础教程这段: 在面向对象编程中,术语对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法.使 ...

  6. C++ Pirmer : 第十五章 : 面向对象程序设计之基类和派生的定义、类型转换与继承与虚函数

    基类和派生类的定义以及虚函数 基类Quote的定义: classs Quote { public: Quote() = default; Quote(cosnt std::string& bo ...

  7. C++ (P160—)多继承 二义性 虚基类 “向上转型”

    1 多继承中,必须给每个基类指定一种派生类型,如果缺省,相应的基类则取私有派生类型,而不是和前一个基类取相同的派生类型 2 一个类的保护成员只能被本类的成员函数或者它的派生类成员函数访问 3 由于c+ ...

  8. C++学习之路—继承与派生(一):基本概念与基类成员的访问属性

    (本文根据<c++程序设计>(谭浩强)总结而成,整理者:华科小涛@http://www.cnblogs.com/hust-ghtao,转载请注明) 1   基本思想与概念 在传统的程序设计 ...

  9. WPF 之 创建继承自Window 基类的自定义窗口基类

    开发项目时,按照美工的设计其外边框(包括最大化,最小化,关闭等按钮)自然不同于 Window 自身的,但窗口的外边框及窗口移动.最小化等标题栏操作基本都是一样的.所以通过查看资料,可按如下方法创建继承 ...

随机推荐

  1. Mac OSX用终端检测文件的sha1值

    打开终端,输入shasum空格然后把文件拖进来回车即可;

  2. 读<<CLR via C#>> 详谈泛型

    1,什么是泛型? 答:泛型是类型的模板,类型是实例(对象)的模板.C#提供了5种泛型:类,接口,委托,结构和方法. 2,使用泛型有什么好处? 答:继承实现的是"代码重用",而泛型实 ...

  3. vs2008+qt进行开发

    第一次接触qt vs,完全小白,网上找资料,各种乱,还大部分是很早以前的,挣扎了好几天终于搞定了, 在此给大家分享. 首先是下载vs2008 (我的项目组项目要求用这个版本),这个比较容易下载:然后是 ...

  4. LXC-Linux Containers介绍

    Linux Containers,Linux的容器,容器嘛,可以想象成一个大的装东西的罐子,罐子口很大,里面可以装很多同样形状,只不过大小不同的小罐子.专业的话,叫做基于容器的操作系统层面的虚拟化技术 ...

  5. PHP 反射 ReflectionClass

    今天遇到了这样一个问题,如下代码: classA.php <?php class ClassA{ public function funcAa(){ } public function func ...

  6. 《Spring3.0就这么简单》

    第一章 认识Spring 1.Spring提供的IOC容器,是Spring大杀器之一.容器将对象之间的依赖关系交给Spring进行控制,采用配制的方式对依赖关系进行描述,由Ioc容器负责依赖类之间的创 ...

  7. Dao层和Service层设计

    1.Dao接口层 public interface IBaseDao<T, ID extends Serializable>{ public abstract Serializable s ...

  8. 链接中 href='#' 和 href='###' 的区别以及优缺点

    首先,<a> 标签 + onclick='{jscode}' 是很常用的一种 js 运用方式,而不使用 href='javascript:{jscode}' 是为了兼容多种浏览器对 < ...

  9. laravel扩展xls处理maatwebsite/excel

    github地址:https://github.com/Maatwebsite/Laravel-Excel 安装: sudo composer require maatwebsite/excel 配置 ...

  10. HTTP的长短连接、长短轮询的区别(转载)

    引言 最近刚到公司不到一个月,正处于熟悉项目和源码的阶段,因此最近经常会看一些源码.在研究一个项目的时候,源码里面用到了HTTP的长轮询.由于之前没太接触过,因此LZ便趁着这个机会,好好了解了一下HT ...