【c/c++】C++静态工具类和单例模式对比学习

文章目录

        • 序言
        • 1. static静态成员
        • 2. C++(伪)静态工具类
        • 3. 单例模式
          • 3.1 单例模式的特点
          • 3.2 单例模式的实现方式
          • 3.3 单例模式的缺点
          • 3.4 Meyer Singleton单例模式
        • 4. (伪)静态工具类 vs 单例模式
          • 4.1 区别
          • 4.2 如何选择
          • 4.3 一些释疑

序言
  • 比较C++ static(伪)静态(工具)类和单例模式的异同,方便工作中正确选用实现方式

  • 说明:Java/C#等高级语言支持静态类,C++不直接支持静态类的概念,但是可以通过一些技巧来实现类似的功能:仅包含静态成员 + 私有构造函数防止类实例化,所以这里称其为伪静态类

1. static静态成员
  • 说明2:C++静态成员和静态函数

    • (1) static修饰成员变量,即为静态成员变量;修改成员方法,即为静态成员方法
    • (2) 静态成员存储在全局变量区,属于类本身,不属于对象;可通过类访问,也可通过实例化后的对象访问;因此静态成员不能在构造函数中初始化,因为构造函数是用来构造单个对象的,而静态成员属于类;也不能用初始化列表来初始化
    • (3) 静态成员在类外初始化时分配内存,程序结束时释放,等同于全局变量
      静态局部变量作用域仅限于函数内部,别的函数不能访问;
      静态全局变量作用域仅限于定义它的源文件,而不是所有源文件
    • (4) 静态成员变量在对象中不占用存储空间
    • (5) 静态方法中只能访问静态成员变量和方法;如果确实需要访问非静态成员,应该通过函数传参方式
  • 静态成员变量只是表面上遵守面向对象,在类中可通过对象调用;一定程度上破坏了面向对象,因为没对象用类名也能直接调用静态成员;静态变量可以看做类外的全局变量和全局函数被封装在了类内部,与非静态变量和成员区别很大

2. C++(伪)静态工具类
  • 静态工具类

    • (1) class声明时使用static,整个类是静态类;
    • (2) 静态类内部全是静态成员,没有非静态成员;
    • (3) 静态类的成员不能有protected或protected internal访问保护修饰符;可以有public、private限制符
    • (4) 静态类不能被实例化,因为不用实例化非静态成员;C++中私有构造函数可以防止类的实例化;静态类存储在全局变量区,生存周期和程序一致
    • (5) 静态类的初始化在类外进行,前面不加static,以免与外部静态变量相混淆;也不能使用this关键字,因为已经实例化并开辟了内存;初始化时不加访问限制符private、public等
    • (6) 静态类不能包含构造函数,但仍可声明静态构造函数以分配初始值或设置某个静态状态;
    • (7) 静态类不能指定任何接口实现,不能有任何实例成员,不能使用abstract或sealed修饰符
    • (8) 静态类成员/函数通过类名::进行访问和调用,不通过对象就可以调用
    • (9) 静态类是密封的,不能被继承,不能拿来做父类
  • C++中构造函数定义为private为什么能防止类的实例化

      1. 私有构造函数无法在类的外部被访问:私有构造函数只能在类的内部被调用,无法在类的外部被访问和调用。因此,无法通过在类的外部实例化对象来创建类的实例
      1. 继承关系下的限制:如果将构造函数定义为protected,子类可以调用父类的protected构造函数来创建父类的实例。但是,如果构造函数是private,子类无法调用父类的private构造函数,因此无法创建父类的实例
  • C++(伪)静态类的实现

头文件 xxx.h

class MapUtil {
// 所有成员均为static
public:static const HdMap& HdMap();static const PercepMap& PercepMap();static const FusionMap& FusionMap();private:static std::unique_ptr<HdMap> hdmap_;static std::mutex hdmap_mutex_;static std::unique_ptr<PercepMap> percep_map_;static std::mutex percep_map_mutex_;static std::unique_ptr<FusionMap> fusion_map_;static std::mutex fusion_map_mutex_;private:					// 不能有protected访问修饰符MapUtil() = delete;		// 私有构造函数防止实例化,静态成员不属于任何对象
};

源文件 xxx.cc

// 不加static也不加访问限制符
std::unique_ptr<HdMap> MapUtil::hdmap_ = nullptr;
std::mutex MapUtil ::hdmap_mutex_;const HdMap& MapUtil::HdMap()
{std::lock_guard<std::mutex> lock(hdmap_mutex_);if (hdmap_ != nullptr) {return *(hdmap_.get());		// 不推荐这样使用
} else {hdmap_ = CreateHdMap();
}
return *(hdmap_.get());
}
3. 单例模式
  • 单例模式设计模式中最基础最简单的一种,也是C++中常见的模式之一
  • 这里重点介绍Meyer单例
3.1 单例模式的特点
  • (1) 一个类只有一个实例
  • (2) 该实例在运行周期内始终存在
  • (3) 该实例可以被全局访问
3.2 单例模式的实现方式
  • (1)饿汉式单例模式
    • 也称为静态单例模式;
    • 程序运行之前就创建,因此是线程安全的;
    • 构造析构函数私有,防止外部创建对象,通过puclic getinstance访问
  • (2)懒汉式单例模式和双重检查锁懒汉式单例模式
    • 在getInstance被调用时才会创建单例对象;
    • 普通懒汉式单例模式,线程不安全;
    • 改进懒汉式单例模式,加双重检查锁,保证线程安全、避免资源浪费
  • (3)Meyer单例模式
    • 利用C++ 11中local static变量的线程安全特性,因此是线程安全的;
    • 构造析构函数私有,不能外部创建对象,通过puclic getinstance访问
    • 在第一次调用时才创建单例,类似懒汉模式,此后每次获取都返回同一实例;
    • 实例内静态局部变量在程序生命周期内只会被创建一次,具有线程安全性,不需加锁
3.3 单例模式的缺点
  • (1)单例模式的代码比较复杂,可能需要在多线程环境下使用同步锁等机制,以保证单例对象的唯一性和线程安全性
  • (2) 单例对象在整个应用程序的生命周期内都存在于内存中,可能会占用较多的系统资源,特别是在单例对象比较庞大或需要长时间运行的情况下;
  • (3)单例模式在某种程度上违反了面向对象设计的一些原则,例如开闭原则、依赖倒置原则等,因为它将对象的创建和使用耦合在一起,不太容易进行单元测试、模块化开发等;
  • 单例模式在一些场景下非常有用,但也不能滥用单例模式,需要确保它是最优解决方案
3.4 Meyer Singleton单例模式
class Singleton
{
public:static Singleton& Instance()
{/* 静态局部变量,第一次调用时初始化,全局生命周期 */static Singleton instance;return instance;}Singleton(const Singleton&) = delete;Singleton(Singleton&&) = delete;Singleton& operator=(const Singleton&) = delete;Singleton& operator=(Singleton&&) = delete;
private:Singleton() = default;~Singleton() = default;
};
  • 不暴露单例的构造析构函数,保证单例类不会通过其他途径被实例化
  • 禁用单例类的拷贝构造、移动构造和赋值构造函数,防止类的唯一实例被拷贝或移动
4. (伪)静态工具类 vs 单例模式
4.1 区别
  • (1) 实例:

    • 静态类没有实例,所有成员都是静态的,不需要实例化;
    • 单例有唯一实例,提供成员的访问接口
  • (2) 初始化:

    • 静态类在第一次加载时初始化;
    • 静态类如懒汉模式可以延迟初始化
  • (3) 扩展性:

    • 静态类通常不能扩展
    • 单例类可以实现接口、继承或者其他使用方法扩展,接口可覆写
  • (4) 全局访问:

    • 静态类通过类名直接访问成员;
    • 单例类提供全局访问点,以在整个程序中共享状态
  • (5) 访问效率:

    • 静态类被认为有更好的访问效率;
  • (6) 可测试性:

    • 单例模式更容易测试
  • (7) 状态维护:

    • 单例模式更方便于维护状态,如果不需要维护任何状态,则适合用静态类;
    • 在一些框架中,单例对象更好管理
  • (8) 面向对象

    • 单例模式比静态类更加面向对象,单例可以使用继承和多态,继承基类,实现自己的接口,提供不同的功能,返回不同的实现对象
4.2 如何选择
  • (1) 静态类适合一些工具类xxx_Util,如地图类MapUtil()
  • (2) 如果单例不维护任何状态,与实例对象无关,不考虑继承和多态,只提供全局访问,适合用静态类
  • (3) 从线程安全、性能、兼容性上来看,也是选用实例化方法为宜
4.3 一些释疑
  • (1) 静态类常驻内存,单例对象不是,所以静态效率高但占内存,类似空间换时间
    • 不是。首次加载后都常驻内存,都放在method table中,效率区别很小,静态类并没有很高效
  • (2) 静态类在堆上分配内存,单例在栈上分配内存
    • 不是。静态成员存储在全局变量区,单例类的对象都有自己的存储区域,普通成员变量存储在栈区
  • (3) 单例要先创建再使用,静态类直接使用,所以静态类更简单
    • 不是。单例的引入是为了更模式化、更面向对象化,单例和静态类的区分是为了解决模式问题,如“人类”和单个人。如果确实需要使用实例,那创建实例对象就是必须的,没有麻烦简单一说,如何选择见5.2所示

 


【参考文章】
[1]. C++静态类实现
[2]. C++中的静态成员
[3]. C++静态成员和静态类
[4]. C++静态成员和静态类,推荐
[5]. C++静态类
[6]. C++单例模式
[7]. C++单例模式介绍,推荐
[8]. 静态变量
[9]. Meyer单例
[10]. Meyer单例,推荐
[11]. 静态类vs单例模式
[12]. 静态类vs单例模式,推荐
[13]. 静态类 vs单例模式

created by shuaixio, 2024.02.18

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

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

相关文章

在k8s中,使用DirectPV CSI作为分布式存储的优缺点

DirectPV 提供了一种直接将物理卷(Physical Volumes)与 Kubernetes 集群中的 Pod 绑定的机制。 利用 DirectPV,你可以将相应的 PV 直接与节点上的物理存储设备(如磁盘)进行绑定,而无需通过网络存储服务(如 NFS 或 Ceph)来提供存储。这种直接访问物理卷的方式,有助于提…

C语言---指针进阶

1.字符指针 int main() {char str1[] "hello world";char str2[] "hello world";const char* str3 "hello world.";const char* str4 "hello world.";if (str3 str4){//常量字符串在内存里面是无法修改的&#xff0c;所以没必要…

springboot/ssm校园菜鸟驿站管理系统Java校园快递取件管理系统

springboot/ssm校园菜鸟驿站管理系统Java校园快递取件管理系统 开发语言&#xff1a;Java 框架&#xff1a;springboot&#xff08;可改ssm&#xff09; vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.…

这是 30 年来创办公司的最佳时机(下篇)

有些很聪明的人没什么成就,主要的原因是不愿意做基础性重复性的工作。 他们有个毛病,一旦达到某个状态,了解了事情的本质,就不愿意再重复去做了。所以,最后她们只能当参谋一样的角色。 真正能做成事情的人,都是能到一线去执行的。要是你聪明、又能干,那成为大才的概率很…

WordPress管理员修改自己用户名的插件Username

有一些站长在刚开搭建WordPress网站时&#xff0c;对于管理员的用户名是随意输入&#xff0c;后来想要修改时发现不懂得如何下手。其实&#xff0c;修改WordPress管理员用户名最快速的方法就是进入数据库直接修改&#xff0c;详见『通过phpMyAdmin直接修改WordPress用户名的图文…

linux 环境下使用gsettings更改alt+tab切屏模式

Linux 操作系统配置 dconf是GNOME3的注册表&#xff0c;可以通过改变dconf中value的值来改变配置&#xff0c;有两种配置方法。第一种是通过可视化GUI dconf-editor进行配置&#xff0c;第二种是通过gsettings command line的方式改变dconf注册表中的value来设置。 dconf-edit…

裸辞5个月,面试了37家公司,终于找到理想工作了

上半年裁员&#xff0c;下半年裸辞&#xff0c;有不少人高呼裸辞后躺平真的好快乐&#xff01;但也有很多人&#xff0c;裸辞后的生活五味杂陈。 面试37次终于找到心仪工作 因为工作压力大、领导PUA等各种原因&#xff0c;今年2月下旬我从一家互联网小厂裸辞&#xff0c;没想…

物联网水域信息化:水质监测智慧云平台

行业背景 由于传统水务企业水质监测和管理技术不足&#xff0c;以及水源污染等问题&#xff0c;确保供水水质达标困难重重。 且传统水务行业信息化手段单一&#xff0c;缺乏对大数据等新技术的应用&#xff0c;一定程度上影响了水务工作的精细化和智能化程度。 系统特点 为…

【plt.pie绘制饼图】:从入门到精通,只需一篇文章!【Matplotlib可视化】

【&#x1f4ca;plt.pie绘制饼图】&#xff1a;从入门到精通&#xff0c;只需一篇文章&#xff01;【Matplotlib可视化】&#xff01; 利用Matplotlib进行数据可视化示例 &#x1f335;文章目录&#x1f335; &#x1f3a8; 一、饼图初探&#xff1a;基本概念与用途&#x1f4a…

Python实现KDJ指标计算:股票技术分析的利器系列(3)

Python实现KDJ指标计算&#xff1a;股票技术分析的利器系列&#xff08;3&#xff09; 介绍算法解释 代码rolling函数介绍计算LLV&#xff08;最低价最小值&#xff09;和HHV&#xff08;最高价最大值&#xff09;计算RSV计算SMA&#xff08;简单移动平均&#xff09; 完整代码…

Linux——信号(1)

在我们使用Linux系统的时候我们经常会使用ctrl c的方式来终止进程&#xff0c;也 会使用kill命令来杀掉进程&#xff0c;评判进程退出的健康程度中也有信号的身影。那 么Linux中的信号到底是什么&#xff1f;今天就由我来介绍Linux中的信号。1. 信号的概念 要了解计算机中的信…

「优选算法刷题」:连续数组

一、题目 给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组&#xff0c;并返回该子数组的长度。 示例 1: 输入: nums [0,1] 输出: 2 说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。 示例 2: 输入: nums [0,1,0] 输出: 2 说明: [0, 1] (或…

mysql在服务器中的主从复制Linux下

mysql在服务器中的主从复制Linux下 为什么要进行主从复制主从复制的原理主从复制执行流程操作步骤主库创建从库创建 测试 为什么要进行主从复制 在业务中通常会有情况&#xff0c;在sql执行时&#xff0c;将表锁住&#xff0c;导致不能进行查询&#xff0c;这样就会影响业务的…

DS:栈和队列的相互实现

创作不易&#xff0c;感谢友友们三连&#xff01;&#xff01; 一、前言 栈和队列的相互实现是用两个栈去实现队列或者是用两个队列去实现栈&#xff0c;这样其实是把问题复杂化的&#xff0c;实际中没有什么应用价值&#xff0c;但是通过他们的相互实现可以让我们更加深入地理…

vue的十大面试题详情

1 v-show与v-if区别 v-if与v-show可以根据条件的结果,来决定是否显示指定内容&#xff1a; v-if: 条件不满足时, 元素不会存在. v-show: 条件不满足时, 元素不会显示(但仍然存在). <div id"app"><button click"show !show">点我</but…

(2024,提示优化,监督微调,强化学习,近端策略优化)用于安全生成文本到图像的通用提示优化器

Universal Prompt Optimizer for Safe Text-to-Image Generation 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. 相关工作 3. 提议的框架 4. 实验 0. 摘要 文本-图像&a…

软件实例分享,酒店酒水寄存管理系统软件教程

软件实例分享&#xff0c;酒店酒水寄存管理系统软件教程 一、前言 以下软件教程以 佳易王酒水寄存管理系统软件V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、寄存的商品名称可以预先设置 2、寄存人可以使用手.机号识别 3、会员充值…

详解4大C语言内存函数【超详细建议点赞收藏】

目录 1. memcpy----内存拷贝1.1 函数介绍1.2 函数使用1.3 模拟实现 2. memmove----重叠内存的数据拷贝2.1 函数介绍2.2 函数使用2.3 模拟实现 3. memcmp----内存比较3.1 函数介绍3.2 函数使用 4.memset----内存设置4.1 函数介绍4.2 函数使用 注意&#xff1a;以下4个内存函数在…

Springboot医院信息管理系统源码 带电子病历和LIS Saas应用+前后端分离+B/S架构

目录 系统特点 技术架构 系统功能 1、 标准数据维护 2、 收费&#xff08;门诊/住院&#xff09;系统 3、 药剂管理系统 4、 医生工作站系统 5、 护士工作站系统 6、电子病历系统 系统优点 云HIS系统简介 云HIS系统功能模块 门急诊挂号管理 门诊收费管理 门诊医…

ansible剧本中的角色

1 roles角色 1.1 roles角色的作用&#xff1f; 可以把playbook剧本里的各个play看作为一个角色&#xff0c;将各个角色打的tasks任务、vars变量、template模版和copy、script模块使用的相关文件等内容放置在指定角色的目录里统一管理&#xff0c;在需要的时候可在playbook中使…