C++特殊类设计

一、设计模式的概念

1、设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。


2、使用设计模式是为了可重用代码、让代码更容易被他人理解、提高代码的可靠性。


3、设计模式一般有如下几个基本要素:模式名称、问题、目的、解决方案、效果、实例代码和相关设计模式,


4、其中的关键元素包括以下四个方面:模式名称 ,问题 ,解决方案 ,效果 。

5、设计模式分为三大类:创建型模式、结构型模式、行为型模式

        <1>创建型模式(5种):工厂方法、抽象工厂方法、单例模式、建造者模式、原型模式
        <2>结构型模式(8种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
        <3>行为型模式(13种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

二、特殊类设计:只能创建一个对象的类(单例模式)

  1. 在我们平时写代码中,单例模式是使用的最多的一种设计模式
  2. 一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理

  3. 单例模式分为:懒汉单例模式,饿汉单例模式,登记时单例模式

2.1 饿汉单例模式

就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。
// 饿汉模式
// 优点:简单
// 缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定。
class Singleton
{
public:static Singleton* GetInstance(){return m_instance;}private:// 构造函数私有Singleton() {};// C++98 防拷贝Singleton(Singleton const&);Singleton& operator=(Singleton const&);// or// C++11Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;static Singleton* m_instance;
};
// 在程序入口之前就完成单例对象的初始化
Singleton* Singleton::m_instance = new Singleton; int main()
{cout << Singleton::GetInstance() << endl;cout << Singleton::GetInstance() << endl;cout << Singleton::GetInstance() << endl;return 0;
}

饿汉单例模式总结:

1、如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来       避免资源竞争,提高响应速度更好
2、饿汉单例模式优点:
            保证全局(整个进程)只有唯一实例对象。
            饿汉模式:一开始就创建对象,特别简单。
3、饿汉单列模式缺点:
            多个单例对象A,B,C假设要求他们之间有依赖关系:依次创建,就无法达到,无法保证顺序。
            可能会导致程序启动很慢。

2.2 懒汉单例模式

如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取
文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,
就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。
// 懒汉
// 优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制。
// 缺点:复杂
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
class Singleton
{
public:static Singleton* GetInstance() {// 注意这里一定要使用Double-Check的方式加锁,才能保证效率和线程安全if (nullptr == m_pInstance) {m_mtx.lock();if (nullptr == m_pInstance) {m_pInstance = new Singleton();}m_mtx.unlock();}return m_pInstance;}// 实现一个内嵌垃圾回收类class CGarbo {public:~CGarbo() {if (Singleton::m_pInstance)delete Singleton::m_pInstance;}};// 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象static CGarbo Garbo;
private:// 构造函数私有Singleton() {};// 防拷贝Singleton(Singleton const&);Singleton& operator=(Singleton const&);static Singleton* m_pInstance; // 单例对象指针static mutex m_mtx; //互斥锁
};
Singleton* Singleton::m_pInstance = nullptr;
Singleton::CGarbo Garbo;
mutex Singleton::m_mtx;
void func(int n)
{cout << Singleton::GetInstance() << endl;
}// 多线程环境下才能演示上面GetInstance()加锁和不加锁的区别
int main()
{thread t1(func, 10);thread t2(func, 10);t1.join();t2.join();cout << Singleton::GetInstance() << endl;cout << Singleton::GetInstance() << endl;
}

懒汉单例模式总结:

  1. 懒汉模式:第一次调用的时候才会创建初始化实例
  2. 如果不加锁是会出现线程安全的问题
  3. 但是加锁是会十分影响性能的,所以引入了双检查
  4. 既要保证线程安全+又要保证效率的问题

三、特殊类设计:不能被拷贝的类

  1. 拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可
  • 对于C++98而言:将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可
class CopyBan
{// ...private:CopyBan(const CopyBan&);CopyBan& operator=(const CopyBan&);//...
};

原因:

设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了
只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了


对于C++11而言: C++11扩展 delete 的用法,delete除了释放 new 申请的资源外,如果在默认成员函数后跟上 =delete ,表示让编译器删除掉该默认成员函数

class CopyBan
{// ...CopyBan(const CopyBan&) = delete;CopyBan& operator=(const CopyBan&) = delete;//...
};

四、特殊类设计:只能在堆上创建对象

基本思路:

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

五、特殊类设计:只能在栈上创建对象的类

方法一:和只能在堆上创建对象的类一样

class StackOnly
{
public:static StackOnly CreateObject(){return StackOnly();}
private:StackOnly(){}
};

还是和上面相同的做法,但是这里就不能禁用拷贝构造了,因为在返回的时候肯定是返回一个局部对象,所以 CreateObject 只能传值返回,但是只要是传值返回就肯定是要拷贝构造,那么如果把拷贝构造禁用了,那么返回的时候就会有问题

方法二:屏蔽new

因为new在底层调用void operator new(size_t size)函数,只需将该函数屏蔽掉即可,同时也要防止定位new

class StackOnly
{
public:StackOnly() {}
private:void* operator new(size_t size);void operator delete(void* p);
};int main()
{StackOnly so;StackOnly* p = new StackOnly;static StackOnly sso;return 0;
}

因为 new 的时候是由两部分构成,第一部分是申请空间调用 operator new ,默认是调用全局的 operator new,再调它的构造函数。但是一个类可以重载专属的 operator new,所以这时肯定就会调用专属的 operator new ,所以我们将 operator new 设为私有,那么这时就调用不动了。

  • 当然也可以用 C++11 的方法去实现

  • 但是这个方法有缺陷,虽然可以在栈上创建对象,不能在堆上创建对象了:

  • 但是可以在静态区去创建对象,所以这个方法是有一些缺陷的

六、特殊类设计:不能被继承的类

对于C++98而言:

  1. C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
  2. 无法继承的原因是父类私有成员在子类不可见
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};
  • 也就是说子类的构造函数想要初始化父类的那一部分,不能自己去对那一部分去初始化,而是要调用父类的构造函数去初始化,所以我们只要将父类的构造函数设为私有的,那么子类就看不到父类的构造函数,也就无法对其初始化,也就不能够被继承
  • 但是这里其实还是不够彻底的:

  • 我们可以看到,其实是可以继承的,但是这里真正限制的是:

  • 也就是子类继承后不能实例化出对象来,但是其实不能实例化出对象来,这个类就费了一半了,因为我们在使用类的时候基本都是实例化出对象,然后通过对象去进行一番操作
  • 但这也是不彻底的,所以才有了 C++11 的一个关键字 final

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/262340.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字信号处理:傅里叶分析

本文主要参考视频如下&#xff1a; 数字信号处理9-1_线性时不变系统对复指数信号的响应_哔哩哔哩_bilibili 傅里叶分析的主要研究内容如下所示&#xff1a; 注意&#xff0c;计算机中使用的离散傅里叶变换并不是离散时间傅里叶变换&#xff1b; 前四种都是理论上的变换方式&…

Elasticsearch:将 IT 智能和业务 KPI 与 AI 连接起来 - 房间里的大象

作者&#xff1a;Fermi Fang 大象寓言的智慧 在信息技术和商业领导力的交叉点&#xff0c;蒙眼人和大象的古老寓言提供了一个富有洞察力的类比。 这个故事起源于印度次大陆&#xff0c;讲述了六个蒙住眼睛的人第一次遇到大象的故事。 每个人触摸大象的不同部位 —— 侧面、象牙…

C 标准库 - <errno.h>

在C语言编程中&#xff0c;<errno.h> 头文件扮演着至关重要的角色&#xff0c;它提供了一个全局变量 errno 以及一系列预定义宏&#xff0c;用于指示系统调用或库函数执行过程中发生的错误。这些宏有助于程序员诊断和处理运行时错误。 errno 变量 extern int errno;err…

RabbitMQ学习整理————基于RabbitMQ实现RPC

基于RabbitMQ实现RPC 前言什么是RPCRabbitMQ如何实现RPCRPC简单示例通过Spring AMQP实现RPC 前言 这边参考了RabbitMQ的官网&#xff0c;想整理一篇关于RabbitMQ实现RPC调用的博客&#xff0c;打算把两种实现RPC调用的都整理一下&#xff0c;一个是使用官方提供的一个Java cli…

Java SpringBoot测试OceanBase

对上篇mysql导入到OceanBase中的数据库进行代码测试&#xff0c;写了个demo包含测试方法&#xff0c;在原mysql库中成功执行&#xff0c;迁移到OceanBase时看是否能不修改业务代码而成功执行测试方法&#xff1a; 代码基于SpringBoot MyBastis测试增删改查、批量新增、多表联…

Redis(十六)缓存预热+缓存雪崩+缓存击穿+缓存穿透

文章目录 面试题缓存预热缓存雪崩解决方案 缓存穿透解决方案 缓存击穿解决方案案例&#xff1a;高并发聚划算业务 总结表格 面试题 缓存预热、雪崩、穿透、击穿分别是什么?你遇到过那几个情况?缓存预热你是怎么做的?如何避免或者减少缓存雪崩?穿透和击穿有什么区别?他两是…

基于docker安装HDFS

1.docker一键安装见 docker一键安装 2.拉取镜像 sudo docker pull kiwenlau/hadoop:1.03.下载启动脚本 git clone https://github.com/kiwenlau/hadoop-cluster-docker4.创建网桥 由于 Hadoop 的 master 节点需要与 slave 节点通信&#xff0c;需要在各个主机节点配置节点…

【ctfshow—web】——信息搜集篇1(web1~20详解)

ctfshow—web题解 web1web2web3web4web5web6web7web8web9web10web11web12web13web14web15web16web17web18web19web20 web1 题目提示 开发注释未及时删除 那就找开发注释咯&#xff0c;可以用F12来查看&#xff0c;也可以CtrlU直接查看源代码呢 就拿到flag了 web2 题目提示 j…

常见消息中间件

ActiveMQ 我们先看ActiveMQ。其实一般早些的项目需要引入消息中间件&#xff0c;都是使用的这个MQ&#xff0c;但是现在用的确实不多了&#xff0c;说白了就是有些过时了。我们去它的官网看一看&#xff0c;你会发现官网已经不活跃了&#xff0c;好久才会更新一次。 它的单机吞…

mysql优化指南之优化篇

二、优化 现在的理解数据库优化有四个维度&#xff0c;分别是&#xff1a; 硬件升级、系统配置、表结构设计、SQL语句及索引。 那优化的成本和效果分别如下&#xff1a; 优化成本&#xff1a;硬件升级>系统配置>表结构设计>SQL语句及索引。 优化效果&#xff1a;…

Java项目:27 基于SSM+JSP实现的大学校园兼职平台

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统介绍 基于SSMJSP实现的大学校园兼职平台分为前台与管理员两块 管理端分为8大模块&#xff0c;分别是用户管理、兼职管理、帖子管理、聊天管理、…

「递归算法」:求根节点到叶节点数字之和

一、题目 给你一个二叉树的根节点 root &#xff0c;树中每个节点都存放有一个 0 到 9 之间的数字。 每条从根节点到叶节点的路径都代表一个数字&#xff1a; 例如&#xff0c;从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。 计算从根节点到叶节点生成的 所有数…

如何构建企业专属GPT

大语言模型&#xff08;LLM&#xff09;具有令人印象深刻的自然语言理解和生成能力&#xff0c; 2022年11月底OpenAI发布了ChatGPT&#xff0c;一跃成为人工智能AI领域的现象级应用。但由于LLM的训练数据集主要来源于互联网数据&#xff0c;企业私域信息并未被LLM所训练&#x…

家用电器全球扩张:如何借助海外网红营销实现助力品牌成长?

随着全球化的深入发展&#xff0c;家用电器市场已不再局限于国内市场&#xff0c;众多品牌纷纷将目光投向海外&#xff0c;寻求更广阔的发展空间。在这个过程中&#xff0c;如何有效地进行海外推广成为品牌面临的一大挑战。近年来&#xff0c;海外网红营销逐渐崭露头角&#xf…

【Spring】IoC容器 控制反转 与 DI依赖注入 配置类实现版本 第四期

文章目录 基于 配置类 方式管理 Bean一、 配置类和扫描注解二、Bean定义组件三、高级特性&#xff1a;Bean注解细节四、高级特性&#xff1a;Import扩展五、基于注解配置类方式整合三层架构组件总结 基于 配置类 方式管理 Bean Spring 完全注解配置&#xff08;Fully Annotatio…

AndroidStudio 2024-2-21 Win10/11最新安装配置(Kotlin快速构建配置,gradle镜像源)

AndroidStudio 2024 Win10/11最新安装配置 教程目的&#xff1a; (从安装到卸载) &#xff0c;针对Kotlin开发配置&#xff0c;gradle-8.2-src/bin下载慢&#xff0c;以及Kotlin构建慢的解决 好久没玩AS了,下载发现装个AS很麻烦,就觉得有必要出个教程了(就是记录一下:嘻嘻) 因…

MariaDB落幕和思考

听过MySQL的基本也都知道 MariaDB。MariaDB由MySQL的创始人主导开发&#xff0c;他早前曾以10亿美元的价格&#xff0c;将自己创建的公司MySQL AB卖给了SUN&#xff0c;此后&#xff0c;随着SUN被甲骨文收购&#xff0c;MySQL的所有权也落入Oracle的手中。传闻MySQL的创始人担心…

vue封装el-table表格组件

先上效果图&#xff1a; 本文包含了具名插槽、作用域插槽、jsx语法三种&#xff1a; Render.vue&#xff08;很重要&#xff0c;必须有&#xff09;: <script> export default {name: "FreeRender",functional: true,props: {scope:Object,render: Functio…

我把springboot项目从Java 8 升级 到了Java 17 的过程总结,愿为君提前踩坑!

项目从jdk8升级到jdk17&#xff0c;我不是为了追求java 17的新特性&#xff08;准确来说也还没有去了解有什么新特性&#xff09;&#xff0c;也不是为了准确与时俱进&#xff0c;永远走在java行列的最前端&#xff0c;纯粹因为项目需要&#xff0c;因为我们都知道&#xff0c;…

【医学大模型 补全主诉】BioGPT + LSTM 自动补全医院紧急部门主诉

BioGPT LSTM 自动补全医院紧急部门主诉 问题&#xff1a;针对在紧急部门中自动补全主诉的问题子问题1: 提高主诉记录的准确性子问题2: 加快主诉记录的速度子问题3: 统一医疗术语的使用子问题4: 减少打字错误和误解子问题5: 提高非特定主诉的处理能力 解法数据预处理神经网络方…