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

这篇具有很好参考价值的文章主要介绍了【c/c++】C++静态工具类和单例模式对比学习。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

序言
  • 比较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文章来源地址https://www.toymoban.com/news/detail-826875.html

到了这里,关于【c/c++】C++静态工具类和单例模式对比学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python入门【​编辑、组合、设计模式_工厂模式实现 、设计模式_单例模式实现、工厂和单例模式结合、异常是什么?异常的解决思路 】(十七)

    👏作者简介:大家好,我是爱敲代码的小王,CSDN博客博主,Python小白 📕系列专栏:python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀 🔥如果感觉博主的文章还不错的

    2024年02月14日
    浏览(44)
  • Java|static关键字的应用【工具类、代码块和单例】

    在上一篇文章讲完了static的一些基础知识后,我们就来说一说这个在应用开发中具体可以怎么使用吧,希望看完这篇文章可以对您有帮助📖 类中都是一些 静态方法 ,每个方法都是以完成一个公用的功能为目的,这个类用来给系统开发人员 共同使用的 一是调用

    2023年04月12日
    浏览(38)
  • C++学习—单例模式

    目录 ​编辑 一,单例模式介绍 二,单例模式下的两种模式  1,饿汉模式 2,懒汉模式   单例:在全局只有一份实例。 单例模式是编程的经典模式之一。 二,单例模式下的两种模式  1,饿汉模式 饿汉模式:在main函数启动前就先把实例化的类对象准备好。 1,提前准备好实

    2024年02月19日
    浏览(32)
  • 设计模式3:单例模式:静态内部类模式是怎么保证单例且线程安全的?

    上篇文章:设计模式3:单例模式:静态内部类单例模式简单测试了静态内部类单例模式,确实只生成了一个实例。我们继续深入理解。 静态变量什么时候被初始化? 这行代码 private static Manager instance = new Manager(); 什么时候执行? 编译期间将.java文件转为.class文件,运行期间

    2024年02月12日
    浏览(46)
  • Java单例模式的五种实现方式 懒汉式 饿汉式 双重校验锁 静态变量 静态内部类 枚举实现单例模式等

    Java单例模式是一种设计模式,用于确保一个类只有一个实例,并提供全局访问点以获取该实例。它通常用于需要共享资源或控制某些共享状态的情况下。 懒汉式:在类加载的时候就创建对象,要再调用方法时才创建对象,减少内存开销。 饿汉式:再类加载的时候就实例化对

    2024年04月27日
    浏览(36)
  • 【单例模式】饿汉式、懒汉式、静态内部类--简单例子

    单例模式是⼀个单例类在任何情况下都只存在⼀个实例,构造⽅法必须是私有的、由⾃⼰创建⼀个静态变量存储实例,对外提供⼀个静态公有⽅法获取实例。 目录 一、单例模式 饿汉式  静态内部类 懒汉式 反射可以破坏单例 道高一尺魔高一丈 枚举 类⼀加载就创建对象,这

    2024年04月23日
    浏览(64)
  • Java 基础进阶篇(一)——— static 静态关键字与单例模式

    static:代表静态的意思,可以修饰成员变量,可以修饰成员方法。 static 修饰方法之后称为 静态方法(类方法) ,修饰成员变量之后称为 静态成员变量(类变量) 。 static 修饰后的成员变量, 可以被类的所有对象共享 (访问、修改) 。 静态成员变量 实例成员变量 概述 有

    2024年02月01日
    浏览(87)
  • 【Java|多线程与高并发】设计模式-单例模式(饿汉式,懒汉式和静态内部类)

    设计模式是一种在软件开发中常用的解决复杂问题的方法论。它提供了一套经过验证的解决方案,用于解决特定类型问题的设计和实现。设计模式可以帮助开发人员提高代码的可重用性、可维护性和可扩展性。 设计模式有很多,本文主要介绍单例模式. 单例模式是一种创建型设

    2024年02月11日
    浏览(55)
  • c++类和对象(拷贝构造、运算符重载、初始化列表、静态成员、友元等)

    拷贝构造函数的特征: 1、拷贝构造函数是构造函数的一个重载形式; 2、拷贝构造函数的参数只有一个且必须是同类类型对象的引用, 使用传值方式编译器直接报错 ,因为会引发无穷递归调用。 在c++中自定义类型 传值传参 的时候要调用拷贝构造函数。 3、若未显式定义,

    2024年02月15日
    浏览(38)
  • 【C++】设计模式-单例模式

    目录 一、单例模式 单例模式的三个要点 针对上述三要点的解决方案 常用的两类单例模式  二、懒汉模式实现 1.基本实现 2.锁+静态成员析构单例 3.双层检查锁定优化 4.双层检查锁定+智能指针 三、饿汉模式实现 1.基础实现 2.嵌套内部类解决内存泄漏 3.智能指针解决内存泄漏

    2024年02月16日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包