特殊类的设计(单类模式)
创始人
2024-03-26 02:04:16
0

一.不能拷贝的类

首先要知道拷贝的场景:拷贝构造函数以及赋值运算符重载,想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

方法1:将这两个函数只声明,不定义(防止编译器默认生成,但不能防止用户可在外面定义),或者把这两个函数设置为私有。

方法2:C++11的方式将这两个函数删除(用delete)。

例如:

class Copyban
{
public:Copyban():_a(99){}	
private://Copyban(Copyban&);//Copyban& operator=(const Copyban&);Copyban(Copyban&) = delete;Copyban& operator=(const Copyban&) = delete;int _a;
};

二.只能在堆上创建对象

1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。 2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建。 例如:
class HeapOnly
{
public:static HeapOnly* CreateObj(){return new HeapOnly;}
private:HeapOnly(){}HeapOnly(const HeapOnly&);//HeapOnly(const HeapOnly&) = delete;
};

三.只能在栈上创建对象

方法1: 将构造函数私有化,后用静态成员函数返回创建的对象。 例如:
class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}
private://StackOnly(StackOnly&) = delete;StackOnly(){}
};

但无法防止在外面拷贝构造在创建对象。

StackOnly obj1 = StackOnly::CreateObj(); static StackOnly obj2(obj1); //在静态区拷贝构造对象 StackOnly* ptr = new StackOnly(obj1); //在堆上拷贝构造对象

方法2:

屏蔽operator new函数和operator delete函数,同时把构造函数私有化,用静态函数返回对象

new和delete默认调用的是全局的operator new函数和operator delete函数,但若是一个类重载了专属的operator new函数和operator delete函数,那么new和delete就会调用这个专属的函数。

例如:

class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}
private:StackOnly(){}void* operator new(size_t size) = delete;void operator delete(void* p) = delete;//void* operator new(size_t size);//void operator delete(void* p);
};

但依旧无法防止在静态区拷贝构造对象。

8ac57f377bc64f52adcf30eff1f5c8df.png

 四.不能被继承的类

只要子类不能调用父类的构造函数即可。

方法1:

与前面类似,将构造函数私有化,用一个静态函数返回对象即可。

方法2:

用c++11的关键字,final,表示该类不能被继承。

例如:

class A  final
{// ....
};

五.只能创建一个对象(单例模式)

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个 访问它的全局访问点,该实例被所有程序模块共享。 比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象同一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。 单例模式有两种实现方式,分别是饿汉模式和懒汉模式: 饿汉模式:程序启动时就创建一个唯一的实例对象 实现方式:
  1. 将构造函数设置为私有,并将拷贝构造函数和赋值运算符重载函数设置为私有或删除,防止外部创建或拷贝对象。
  2. 提供一个指向单例对象的static指针,并在程序入口之前完成单例对象的初始化。
  3. 提供一个全局访问点获取单例对象。
例如:
class Singleton
{
public://3、提供一个全局访问点获取单例对象static Singleton* GetInstance(){return _inst;}
private://1、将构造函数设置为私有,并防拷贝Singleton(){}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;//2、提供一个指向单例对象的static指针static Singleton* _inst;
};
//在程序入口之前完成单例对象的初始化
Singleton* Singleton::_inst = new Singleton;

赋值重载是对于已经存在的对象,这里可以不做处理。

关于单例模式(饿汉实现)线程安全的问题:

饿汉模式是在程序运行主函数之前就完成了单例对象的创建,由于main函数之前是不存在多线程的,因此饿汉模式下单例对象的创建过程是线程安全的。后面访问这个对象是一个读的操作,也不会造成线程不安全。

 

懒汉模式:

  1. 将构造函数设置为私有,并将拷贝构造函数和赋值运算符重载函数设置为私有或删除,防止外部创建或拷贝对象。
  2. 提供一个指向单例对象的static指针,并在程序入口之前先将其初始化为空。
  3. 提供一个全局访问点获取单例对象。

例如:

在获取单例对象时进行加锁处理,防止多线程时创建多个对象。

class Singleton
{
public://3、提供一个全局访问点获取单例对象static Singleton* GetInstance(){//加锁if (_inst == nullptr){_inst = new Singleton;}//解锁return _inst;}
private://1、将构造函数设置为私有,并防拷贝Singleton(){}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;//2、提供一个指向单例对象的static指针static Singleton* _inst;
}//在程序入口之前先将static指针初始化为空
Singleton* Singleton::_inst = nullptr;
当对象被创建出来之后,只是进行读操作,没必要再加锁,改进后:当该指针不为空(对象已创建)后直接返回,没必要加锁。
static Singleton* GetInstance(){if (_inst == nullptr){//加锁if (_inst == nullptr){_inst = new Singleton;}//解锁}return _inst;}

 

 

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...