特殊类的设计(单类模式)
创始人
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;}

 

 

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...