目录
一.不允许被拷贝
二.只能在堆上创建对象
三.只能在栈上创建对象
四.不允许被继承
五.只能创建一个对象(单例模式)
1.饿汉模式
2.懒汉模式
3.比较
前言:一些对于类的设计,比如单例模式等,是比较有用的一种特殊类的设计。
一.不允许被拷贝
拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。
(1)C++98:将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。
class CopyBan
{
public:private:CopyBan(const CopyBan&);CopyBan& operator=(const CopyBan&);
};
(2)C++11:C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上=delete,表示让编译器删除掉该默认成员函数。
class CopyBan
{
public:CopyBan(const CopyBan&) = delete;CopyBan& operator=(const CopyBan&) = delete;
};
二.只能在堆上创建对象
① 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
② 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
class HeapOnly
{
public:static HeapOnly* CreatObj(){return new HeapOnly;}HeapOnly(const HeapOnly&) = delete;private:// 构造函数私有HeapOnly(){}
};
三.只能在栈上创建对象
同上将构造函数私有化,然后设计静态方法创建对象返回即可。
class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}StackOnly(const StackOnly&) = delete;
private:// 构造函数私有StackOnly(){}
};
四.不允许被继承
C++98:
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};
C++11:C++11给了final函数,如果继承就会报错
class A final
{};
五.只能创建一个对象(单例模式)
设计模式:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。设计模式就像是代码中的孙子兵法。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模
式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
单例模式:
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
单例模式有两种实现模式:
1.饿汉模式
无论之后用不用,程序启动时就创建一个唯一的实例对象。
class Singleton
{
public:static Singleton* GetInstance(){return _spInst;}
private:Singleton(){}Singleton(const Singleton&) = delete;// static Singleton _sInst; // 声明static Singleton* _spInst; // 声明int _a;
};// Singleton Singleton::_sInst; // 定义
Singleton* Singleton::_spInst = new Singleton; // 定义
如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好
2.懒汉模式
如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。
第一种万能写法:
class Singleton
{
public:static Singleton* GetInstance(){// 保护第一次,后续不需要加锁// 双检查加锁if (_pInstance == nullptr){unique_lock<mutex> lock(_mtx);if (_pInstance == nullptr){_pInstance = new Singleton;}}return _pInstance;}private:// 构造函数私有Singleton(){};// C++11Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;static Singleton* _pInstance;static mutex _mtx;
};
第二种C++11写法:
class Singleton
{
public:static Singleton* GetInstance(){// 局部的静态对象,第一次调用时初始化// 在C++11之前是不能保证线程安全的// C++11之前局部静态对象的构造函数调用初始化并不能保证线程安全的原子性。// C++11的时候修复了这个问题,所以这种写法,只能在支持C++11以后的编译器上玩static Singleton _s;return &_s;}private:// 构造函数私有Singleton() {};// C++11Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;
};
3.比较
(1)饿汉模式特点
较为简单,初始化顺序不确定,如果有依赖关系就会有问题。饿汉模式对象初始化满且多分饿汉单例对象会影响程序启动。
(2)懒汉模式特点
较为复杂一点,第一次调用时需要初始化,可以控制初始化顺序,延迟加载初始化,不影响程序启动。