C++笔记之智能指针和单例、依赖注入结合使用

C++笔记之智能指针和单例、依赖注入结合使用

参考笔记:
1.C++笔记之静态成员函数可以在类外部访问私有构造函数吗?
2.C++笔记之设计模式:setter函数、依赖注入
3.C++笔记之两个类的实例之间传递参数——通过构造函数传递类对象的方法详细探究
4.C++笔记之智能指针和单例、依赖注入结合使用
5.C++笔记之两个类的实例之间传递参数的各种方法

code review!

文章目录

  • C++笔记之智能指针和单例、依赖注入结合使用
    • 例1.一个类不使用单例,另一个类使用单例
    • 例2.两个类都使用单例,并且通过getInstance()传入类的实例
    • 例3.std::make_unique不能访问私有的构造函数
    • 例4.不通过友元,通过静态成员函数在类外部调用类私有的构造函数

在这里插入图片描述

例1.一个类不使用单例,另一个类使用单例

在这里插入图片描述

运行
在这里插入图片描述

代码

#include <iostream>
#include <memory>class Logger {
private:Logger() {}  // 私有构造函数,防止外部实例化public:static Logger& getInstance() {static Logger instance;  // 静态局部变量确保只有一个实例return instance;}void log(const std::string& message) {std::cout << "Log: " << message << std::endl;}
};class Service {
private:std::shared_ptr<Logger> logger;public:Service(std::shared_ptr<Logger> logger) : logger(logger) {}void doSomething() {logger->log("Service is doing something.");}
};int main() {// 在依赖注入的方式下,创建 Service 实例并传入 Logger 实例Service service(std::make_shared<Logger>(Logger::getInstance()));// 使用 Service 实例service.doSomething();return 0;
}

例2.两个类都使用单例,并且通过getInstance()传入类的实例

在这里插入图片描述

运行
在这里插入图片描述

代码

#include <iostream>
#include <memory>class Logger {private:Logger() {} // 私有构造函数,防止外部实例化public:static std::shared_ptr<Logger> getInstance() {static std::shared_ptr<Logger> instance = std::shared_ptr<Logger>(new Logger());return instance;}void log(const std::string &message) {std::cout << "Log: " << message << std::endl;}
};class Service {private:std::shared_ptr<Logger> logger;Service(const std::shared_ptr<Logger> &logger) : logger(logger) {}public:static std::shared_ptr<Service> getInstance(const std::shared_ptr<Logger> &logger) {static std::shared_ptr<Service> instance = std::shared_ptr<Service>(new Service(logger));return instance;}void doSomething() {logger->log("Service is doing something.");}
};int main() {// 创建 Logger 实例(智能指针管理)std::shared_ptr<Logger> logger = Logger::getInstance();// 创建 Service 实例并传入 Logger 实例std::shared_ptr<Service> service = Service::getInstance(logger);// 使用 Logger 实例logger->log("Logging from main");// 使用 Service 实例service->doSomething();return 0;
}

例3.std::make_unique不能访问私有的构造函数

在这里插入图片描述

编译报错:
在这里插入图片描述

这段代码存在一些小问题:

Service 类的 getInstance 方法中,你使用了 std::make_unique 来创建一个 Service 实例,但是 Service 的构造函数是私有的,不能直接使用 make_unique。你应该改用 std::shared_ptr<Service>(new Service(logger)) 来创建实例,就像在 Logger 类中的 getInstance 方法中一样。

代码

#include <iostream>
#include <memory>class Logger {private:Logger() {} // 私有构造函数,防止外部实例化public:static std::shared_ptr<Logger> getInstance() {static std::shared_ptr<Logger> instance = std::shared_ptr<Logger>(new Logger());return instance;}void log(const std::string &message) {std::cout << "Log: " << message << std::endl;}
};class Service {private:std::shared_ptr<Logger> logger;Service(const std::shared_ptr<Logger> &logger) : logger(logger) {}public:static std::shared_ptr<Service> getInstance(const std::shared_ptr<Logger> &logger) {static std::shared_ptr<Service> instance = std::make_unique<Service>(logger);return instance;}void doSomething() {logger->log("Service is doing something.");}
};int main() {// 创建 Logger 实例(智能指针管理)std::shared_ptr<Logger> logger = Logger::getInstance();// 创建 Service 实例并传入 Logger 实例std::shared_ptr<Service> service = Service::getInstance(logger);// 使用 Logger 实例logger->log("Logging from main");// 使用 Service 实例service->doSomething();return 0;
}

例4.不通过友元,通过静态成员函数在类外部调用类私有的构造函数

在这里插入图片描述

运行
在这里插入图片描述

将实例的创建和初始化封装在了名为 createInstance 的公共静态成员函数中。这个函数在类的外部被调用时,会调用私有构造函数创建一个实例,并返回一个指向这个实例的智能指针。

通过这种方式,你不需要将 std::make_unique 声明为友元函数,也不需要使用特定的友元声明。而是通过公共静态成员函数间接地在类的外部创建实例,从而绕过了直接访问私有构造函数的问题。

构造函数不是静态成员,它们属于实例化的过程,而不是类本身的静态成员。

在C++中,构造函数不是静态成员,它们是用于创建类的实例的特殊成员函数。私有构造函数意味着不能在类的外部直接调用它来创建实例。这是单例模式的一个关键概念,它确保只有一个实例被创建。

而使用公共静态成员函数(如 createInstance)的优势在于,它可以在类的外部创建实例。这是因为静态成员函数不依赖于特定实例,所以它们可以在没有创建对象的情况下被调用。通过在公共静态成员函数中调用私有构造函数,你可以在类的外部创建类的实例。

所以,使用公共静态成员函数解决单例模式中私有构造函数访问问题的关键在于,它提供了一种通过类的内部机制(即静态成员函数)来间接创建实例的方式,绕过了私有构造函数不能直接在外部调用的限制。

代码

#include <iostream>
#include <memory>class Dependency {public:void doSomething() {std::cout << "Dependency is doing something." << std::endl;}
};class Singleton {private:Singleton() { /* 构造函数私有化 */}static std::unique_ptr<Singleton> instance;std::unique_ptr<Dependency> dependency; // 保存依赖项的指针public:// 创建 Singleton 实例的公共静态函数static std::unique_ptr<Singleton> createInstance() {return std::unique_ptr<Singleton>(new Singleton);}// 获取 Singleton 实例的公共静态函数static Singleton &getInstance() {if (!instance) {instance = createInstance();                           // 创建实例instance->dependency = std::make_unique<Dependency>(); // 初始化依赖项}return *instance;}void useDependency() {dependency->doSomething();}// 其他成员函数
};// 初始化静态成员变量
std::unique_ptr<Singleton> Singleton::instance = nullptr;int main() {// 创建 Singleton 实例std::unique_ptr<Singleton> singleton = Singleton::createInstance();// 使用注入的依赖项进行操作singleton->useDependency();return 0;
}

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

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

相关文章

Linux部署RocketMQ并使用SpringBoot创建生产、消费者

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;RocketMQ、消息队列☀️每日 一言&#xff1a;在你心灰意冷、心烦意乱时也不要停下你的脚步&#xff01; 一、前言 RocketMQ&#xff08;Apache RocketMQ&#xff09;是一种开源的分布式消息中间…

SOLIDWORKS中多实体文件到装配体的转换技巧

我们在做机械等工程设计中&#xff0c;有时为了节省时间&#xff0c;需要把多实体的“零件”&#xff0c;直接转换为装配体&#xff0c;不再另外装配&#xff0c;这样能大大简化设计的操作时间&#xff0c;复杂程度。 在这里&#xff0c;我们首先要了解&#xff0c;SOLIDWORKS文…

比较差值结构的两种排斥作用

( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有3个节点&#xff0c;AB训练集各由6张二值化的图片组成&#xff0c;让差值结构中有两个点&#xff0c;一种情况两个点都属于A&#xff0c;一种情况两个点分别来自A和B。排列组合所有可能&#xff0c;统计迭代次数并排序。…

【单片机】有人WH-LTE-7S1 4G cat1 模块连接服务器,教程,记录

文章目录 4G cat1 模块封装引脚名称功能拓扑图串口模块调试WH-LTE-7S1 4G cat1 模块 我买的这个模块内置了电信卡&#xff0c;不用插电话卡就能用&#xff0c;要插也行&#xff0c;在背面。 ⚫ 5-16V 宽电压供电 ⚫ LTE Cat 1&#xff0c;搭载 4G 网络&#xff0c;低时延&…

webassembly003 ggml ADAM (暂记)

Adam优化器的工作方式是通过不断更新一阶矩估计和二阶矩估计来自适应地调整学习率&#xff0c;并利用动量法来加速训练过程。这种方式可以在不同的参数更新方向和尺度上进行自适应调整&#xff0c;从而更有效地优化模型。 https://arxiv.org/pdf/1412.6980.pdf 参数 这些参数…

Linux通过libudev获取挂载路径、监控U盘热拔插事件、U盘文件系统类型

文章目录 获取挂载路径监控U盘热拔插事件libusb 文件系统类型通过挂载点获取挂载路径添libudev加库 获取挂载路径 #include <stdio.h> #include <libudev.h> #include <string.h>int main() {struct udev *udev;struct udev_enumerate *enumerate;struct ud…

EVO大赛是什么

价格是你所付出的东西&#xff0c;而价值是你得到的东西 EVO大赛是什么&#xff1f; “EVO”大赛全称“Evolution Championship Series”&#xff0c;是北美最高规格格斗游戏比赛&#xff0c;大赛正式更名后已经连续举办12年&#xff0c;是全世界最大规模的格斗游戏赛事。常见…

bpmnjs Properties-panel拓展(属性设置篇)

最近有思考工作流相关的事情&#xff0c;绘制bpmn图的工具认可度比较高的就是bpmn.js了&#xff0c;是一个基于node.js的流程图绘制框架。初始的框架只实现了基本的可视化&#xff0c;想在xml进行客制化操作的话需要拓展&#xff0c;简单记录下几个需求的实现过程。 修改基础 …

Transformer (Attention Is All You Need) 论文精读笔记

Transformer(Attention Is All You Need) Attention Is All You Need 参考&#xff1a;跟李沐学AI-Transformer论文逐段精读【论文精读】 摘要&#xff08;Abstract&#xff09; 首先摘要说明&#xff1a;目前&#xff0c;主流的序列转录&#xff08;序列转录&#xff1a;给…

【数据结构】排序(插入、选择、交换、归并) -- 详解

一、排序的概念及其运用 1、排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记…

Go 结构体

现在有一个需求&#xff0c;要求存储学生的详细信息&#xff0c;例如&#xff0c;学生的学号&#xff0c;学生的姓名&#xff0c;年龄&#xff0c;家庭住址等。按照以前学习的存储方式&#xff0c;可以以如下的方式进行存储&#xff1a; 通过定义变量的信息&#xff0c;进行存储…

数字电路-二进制学习

什么是二进制&#xff1f; 数字电路 中 只有 高电平 和低电平 就是 1 和0 进位规则是“逢二进一”&#xff0c;借位规则是“借一当二”。 二进制、八进制 、十进制、十六进制 二进制 有两个数来表示 &#xff1a; 0、1 八进制 有8个数来表示 &#xff1a; 0、1、2、3、4、…

基于RabbitMQ的模拟消息队列之二---创建项目及核心类

一、创建项目 创建一个SpringBoot项目&#xff0c;环境&#xff1a;JDK8&#xff0c;添加依赖&#xff1a;Spring Web、MyBatis FrameWork(最主要&#xff09; 二、创建核心类 1.项目分层 2.核心类 在mqserver包中添加一个包&#xff0c;名字为core&#xff0c;表示核心类…

uniapp 项目实践总结(一)uniapp 框架知识总结

导语&#xff1a;最近开发了一个基于 uniapp 框架的项目&#xff0c;有一些感触和体会&#xff0c;所以想记录以下一些技术和经验&#xff0c;在这里做一个系列总结&#xff0c;算是对自己做一个交代吧。 目录 简介全局文件全局组件常用 API条件编译插件开发 简介 uniapp 是…

openGauss学习笔记-47 openGauss 高级数据管理-权限

文章目录 openGauss学习笔记-47 openGauss 高级数据管理-权限47.1 语法格式47.2 参数说明47.3 示例 openGauss学习笔记-47 openGauss 高级数据管理-权限 数据库对象创建后&#xff0c;进行对象创建的用户就是该对象的所有者。数据库安装后的默认情况下&#xff0c;未开启三权分…

使用ELK(ES+Logstash+Filebeat+Kibana)收集nginx的日志

文章目录 Nginx日志格式修改配置logstash收集nginx日志引入Redis收集日志写入redis从redis中读取日志 引入FilebeatFilebeat简介Filebeat安装和配置 配置nginx转发ES和kibanaELK设置账号和密码 书接上回&#xff1a;《ELK中Logstash的基本配置和用法》 Nginx日志格式修改 默认…

Gorilla LLM:连接海量 API 的大型语言模型

如果你对这篇文章感兴趣&#xff0c;而且你想要了解更多关于AI领域的实战技巧&#xff0c;可以关注「技术狂潮AI」公众号。在这里&#xff0c;你可以看到最新最热的AIGC领域的干货文章和案例实战教程。 一、前言 在当今这个数字化时代&#xff0c;大型语言模型&#xff08;LLM…

利用多种机器学习方法对爬取到的谷歌趋势某个关键词的每日搜索次数进行学习

大家好&#xff0c;我是带我去滑雪&#xff01; 前一期利用python爬取了谷歌趋势某个关键词的每日搜索次数&#xff0c;本期利用爬取的数据进行多种机器学习方法进行学习&#xff0c;其中方法包括&#xff1a;随机森林、XGBOOST、决策树、支持向量机、神经网络、K邻近等方法&am…

聚类分析 | MATLAB实现基于DBSCAD密度聚类算法可视化

聚类分析 | MATLAB实现基于LP拉普拉斯映射的聚类可视化 目录 聚类分析 | MATLAB实现基于LP拉普拉斯映射的聚类可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于DBSCAD密度聚类算法可视化&#xff0c;MATLAB程序。 使用带有KD树加速的dbscan_with_kdtree函数进行…

uniapp项目实战系列(1):导入数据库,启动后端服务,开启代码托管

目录 前言前期准备1.数据库的导入2.运行后端服务2.1数据库的后端配置2.2后端服务下载依赖&#xff0c;第三方库2.3启动后端服务 3.开启gitcode代码托管 ✨ 原创不易&#xff0c;还希望各位大佬支持一下&#xff01; &#x1f44d; 点赞&#xff0c;你的认可是我创作的动力&…