【C++】特殊类的设计 | 类型转换

文章目录

  • 1. 特殊类的设计
    • 单例模式
      • 饿汉模式
        • 具体代码
      • 懒汉模式
        • 具体代码
      • 懒汉模式和饿汉模式的优缺点
  • 2. C++的类型转换
    • C语言的类型转换
    • C++的类型转换
      • static_cast
      • reinterpret_cast
      • const_cast
      • dynamic_cast

1. 特殊类的设计

单例模式

设计模式是 被反复使用 多数人知晓 经过分类的、代码设计经验的总结


单例模式:
一个类只能创建一个对象 即单例模式,该模式可以保证系统中该类只有一个实例

单例模式分为饿汉模式和懒汉模式

饿汉模式

一开始就创建对象(main函数之前)

假设想要vector数组全局只有一份
所以进行限制,使之不能随意创建对象 即将构造函数私有化

若想要创建对象,则通过公有的成员函数getinstallce创建
为了保证每次获取的都是同一个对象,就定义了一个静态的类类型的指针 _p
而静态的成员变量,需要在类外面初始化


在定义静态成员变量时 创建对象


此时也可添加add增加和print打印的功能

定义私有的string数组 _v,使用其push_back 添加数据str,并使记录数字+1


使用print函数打印数据


由于getinstallce函数返回值是一个指针,所以需要使用->去访问add或者print函数


还可以通过设置锁进行多线程间的安全访问

设置私有锁


由于getinstallce函数返回值是一个静态的指针,所以无论是线程t1还是线程t2都可以访问到该函数
并通过该函数调用add或者 print函数
使用to_string 将任意类型转化为string

具体代码

饿汉模式
class stu
{
public:
	static stu* getinstallce()
	{
		return _p;
	}
	void add(const string& str)
	{
		_mtx.lock();//加锁
		_v.push_back(str);
		++_x;
		_mtx.unlock();//解锁
	}
	void print()
	{
		_mtx.lock();//加锁
		for (auto& e : _v)
		{
			cout << e << " ";
			cout << endl;
		}
		_mtx.unlock();//解锁
	}
private:
	//限制类外不能随意创建对象
	//构造函数私有化
	stu(int x=0)
		:_x(x)
	{
	}
private:
	mutex _mtx;
	int _x=0;
	vector<string>_v;
	static stu* _p;
};
//static成员变量在类外定义
stu* stu:: _p = new stu;


int main()
{
	int n = 10;
	thread t1([n]() {
		for (int i = 0; i < n; i++)
		{
			stu::getinstallce()->add("t1线程:"+to_string(i));
		}
		});
	thread t2([n]() {
		for (int i = 0; i < n; i++)
		{
			stu::getinstallce()->add("t2线程:" + to_string(2*i));
		}
		});
	t1.join();
	t2.join();
	stu::getinstallce()->print();
}
int main()
{
	stu::getinstallce()->add("张三");
	stu::getinstallce()->add("李四");
	stu::getinstallce()->print();//打印
	return 0;
}

懒汉模式

第一次访问实例对象时创建(第一次调用getinstallce函数时创建)

在饿汉模式的代码的基础上进行改造


在定义静态成员变量时设置为空


若_p指针为空,在创建对象,并返回
在调用getinstallce函数时才创建对象


虽然看似没有问题,但是在多线程下还存在线程安全的问题

定义一个静态锁,用于保护getinstallce函数中的实例对象


在初始化时,是不需要显示给值的


每次获取对象都要加锁解锁,但实际上只需要保证第一次即可


这样的写法依旧是不行的,当两个线程t1 t2同时进入if循环中,
当线程t1 new后解锁,线程t2获取锁,继续new,就会造成覆盖 丢失数据


所以采用双检查加锁的方式

具体代码

//懒汉模式
class stu
{
public:
	static stu* getinstallce()
	{
		//双检查加锁
		if (_p == nullptr)
		{
			_imtx.lock();//加锁
			if (_p == nullptr)
			{
				_p = new stu;
			}
			_imtx.unlock();//解锁
		}
		return _p;
	}
	void add(const string& str)
	{
		_mtx.lock();//加锁
		_v.push_back(str);
		++_x;
		_mtx.unlock();//解锁
	}
	void print()
	{
		_mtx.lock();//加锁
		for (auto& e : _v)
		{
			cout << e << " ";
			cout << endl;
		}
		_mtx.unlock();//解锁
	}
	//特殊情况下释放单例对象
	static void delinstance()
	{
		_imtx.lock();
		if (_p)
		{
			delete _p;
			_p = nullptr;
		}
		_imtx.unlock();
	}
private:
	//限制类外不能随意创建对象
	//构造函数私有化
	stu(int x = 0)
		:_x(x)
	{
	}
	
	//防拷贝
	stu(const stu& s) = delete;
	stu& operator=(const stu& s) = delete;

private:
	static mutex _imtx;
	mutex _mtx;
	int _x = 0;
	vector<string>_v;
	static stu* _p;
};
//static成员变量在类外定义	 
stu* stu::_p = nullptr;
//将静态锁在类外初始化
mutex stu::_imtx;


懒汉模式和饿汉模式的优缺点

饿汉模式的缺点:
1.若单例对象初始化很慢(如初始化动作多),main函数之前就要申请,暂时不需要使用 就会造成 占用资源、程序启动会变慢受影响
2.若两个单例都是饿汉,并且有依赖关系,要求单例1先创建,单例2再创建,饿汉无法控制顺序,懒汉才可以

(两者是懒汉,则都是使用 成员的静态指针进行new创建对象的,谁先new是控制不住的
而两者都是饿汉,则都是在getinstallce函数中创建对象,
可以控制单例1先在getinstallce函数中创建对象,再让单例2在getinstallce函数中创建对象)

饿汉模式的优点:
优点只有一个,简单

懒汉完美的解决了上面饿汉的问题,变得相对更复杂一点

2. C++的类型转换

C语言的类型转换

C语言有隐式类型转换 和显式类型转换

i为int类型,想要转化为double类型,就需要进行隐式类型转换
即 先将i赋值给一个double类型的临时变量,再通过临时变量赋值给d

p作为一个指针,i作为一个int类型变量,虽然都是4个字节,但是意义不同,所以不能互相转,只能进行显式类型转换
即 将int*类型的指针强转为int类型

C++的类型转换

隐式类型转化 存在精确度丢失的问题
显式类型转化 存在代码不够清晰的问题
所以C++提出了自己的类型转化风格,引入四种强制类型转换操作符
static_cast reinterpret_cast const_cast dynamic_cast

static_cast

static_cast对应c语言中的隐式类型转换
两个变量 是相关的类型 (double和int)

把int类型转化为double类型

reinterpret_cast

reinterpret_cast对应C语言的显式强制类型转换
两个变量 是不相关的类型 (int和int*)

把int类型转化为 int*类型

const_cast

去掉const属性

a为const int类型,转化为&a后,类型为const int*
通过const_cast后,b等待类型为int*类型,可以对b解引用修改
a的值依旧为10,不会被修改
而b的值为5

因为编译器进行优化,把a的值放入寄存器中,而b所修改实际上是寄存器的a值而不是内存中的a值,所以a依旧为10

dynamic_cast

C++独有的

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
父类作为上 ,子类作为下


向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)


父类对象是无法转换为子类对象的


向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的,直接强制转换是不安全的)

A作为父类,B作为子类
所以将p强制转换为B*,存在风险,如果B有自己的成员,用指针可以访问这些成员,但这个访问就强制越界了,多开的一部分空间不属于你的


dynamic_cast 会先进行检查,若指向父类对象,则转换失败,若指向子类对象,则转换成功

注意:
dynamic_cast只能用于父类含有虚函数的类

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

React之生命周期

React之生命周期 旧版本&#xff0c;函数组件是没有生命周期的。新版本中通过useEffect触发函数的生命周期 一、基于类组件的生命周期 React的组件生命周期分为挂载阶段、更新阶段和销毁阶段。因为React的state不具有Vue的响应式&#xff0c;所以并没有create阶段 1、挂载阶段&…

第八章:list类

系列文章目录 文章目录 系列文章目录前言list的介绍及使用list的介绍list的使用list的构造函数list的迭代器list的容量list的成员访问list的增删改查 list与vector的对比总结 前言 list是STL的一种链表类&#xff0c;可以在常数范围内在任意位置进行插入和删除的序列式容器。 …

专访伊士曼中国区高管赵志伟:以创新应对新能源汽车后市场变化

受访人&#xff1a;伊士曼高性能膜事业部中国区商务总监赵志伟 新能源汽车发展至规模化阶段&#xff0c;以贴膜、保养维修为主的后市场产业迎来快速崛起&#xff0c;新能源消费者在汽车贴膜、改装和养护领域也表现出比燃油车更高频的需求度。 作为一家全球特种材料公司&#x…

MySQL~DQL查询语句

一、DQL:查询语句 1、排序查询 语法&#xff1a; order by 子句 ​ order by 排序字段1 排序方式1 &#xff0c;排序字段2 排序方2... 排序方式&#xff1a; ASC&#xff1a;升序[默认] DESC&#xff1a;降序 在SQL语句中永远排序最后 注&#xff1a; 如果有多个排序条…

立创EDA学习

学习树莓派3B的板子发现有个扩展板比较好&#xff0c;自己最好画一个&#xff0c;反正免费。 学习视频&#xff1a;立创EDA&#xff08;专业版&#xff09;电路设计与制作快速入门。 下载专业版&#xff0c;并激活。【分专业版和标准版&#xff0c;专业版也是免费的】 手机…

学习自动化测试该怎么学?6个步骤轻松拿捏

自动化测试作为脱离手工测试的基本核心内容&#xff0c;其重要性不言而喻了&#xff0c;而且我们来看近期大厂的一些招聘信息显示&#xff0c;基本上自动化测试是必备前提&#xff0c;没有这个基本就不用谈后面的问题了&#xff0c;下面我们通过联想集团的一个软件测试工程师的…

购物车功能实现(小兔鲜儿)【Vue3】

购物车 流程梳理和本地加入购物车实现 购物车业务逻辑梳理拆解 整个购物车的实现分为两个大分支, 本地购物车操作和接口购物车操作由于购物车数据的特殊性,采取Pinia管理购物车列表数据并添加持久化缓存 本地购物车 - 加入购物车实现 添加购物车 基础思想&#xff1a;如果…

Ceph社区上游正式合入openEuler原生支持,并通过CI持续验证

作为覆盖全场景应用、支持多样性算力的面向数字基础设施的开源操作系统&#xff0c;openEuler始终遵循“上游优先”的策略&#xff0c;帮助上游开源软件原生支持openEuler&#xff0c;让openEuler系操作系统的用户可以在开发、集成、使用这些开源软件或基于这些开源软件的产品和…

市面上的ipad国产触控笔怎么样?精选的性价比电容笔

要知道&#xff0c;真正的苹果品牌的那款原装电容笔&#xff0c;光是一支电容笔就价格近千元。实际上&#xff0c;平替电容笔对没有太多预算的用户是个不错的选择。一支苹果品牌的电容笔&#xff0c;价格是平替品牌的四倍&#xff0c;但电容笔的书写效果&#xff0c;却丝毫不逊…

idea如何解决导入的项目不是Maven工程(文件下面没有蓝色的方格)二

简介&#xff1a; Maven项目导入&#xff0c;idea不识别项目 解决方法&#xff1a; 选中pom.xml -- 右键 -- Add as Maven Project

技术实力加速企业上云,联想混合云获评专有云优秀案例入选混合云全景图四大方向

7月25-26日&#xff0c;由中国信息通信研究院、中国通信标准化协会联合主办的第十届可信云大会在京顺利召开。大会重磅发布了云计算白皮书&#xff08;2023年&#xff09;、《混合云产业全景图&#xff08;2023&#xff09;》、中国算力服务研究报告、中国云计算发展指数报告等…

Golang速成

目录 Golang 语言特性Golang的优势Golang 的应用场景Golang 的不足 基础语法变量的声明常量与 iotastring字符串遍历strings 包bytes 包strconv 包unicode 包 循环语句range 函数多返回值init 函数闭包import 导包匿名函数 指针defer切片 slice数组sliceslice 操作… mapmap 的…

MySQL InnoDB死锁原因及改善建议(InnoDB Deadlocks)

死锁是事务型数据库中一种现象&#xff0c;为了在高并发环境下不出错&#xff0c;数据库引入了"锁"这一数据结构来控制资源的并发访问&#xff0c;但也会导致死锁。 目录 一、死锁概念 1.1 死锁的原因 1.2 死锁监测 二、死锁演示 2.1 死锁生成过程 2.2 死锁信息查看 …

EtherNet/IP转Modbus网关以连接AB PLC

本案例为西门子S7-1200 PLC通过捷米特Modbus转EtherNet/IP网关捷米特JM-EIP-RTU连接AB PLC的配置案例。 网关分别从ETHERNET/IP一侧和MODBUS一侧读写数据&#xff0c;存入各自的缓冲区&#xff0c;网关内部将缓冲区的数据进行交换&#xff0c;从而实现两边数据的传输。 网关做为…

vue 实现拖拽效果

实现方式&#xff1a;使用自定义指令可以实现多个面板拖拽互不影响 1.自定义指令 js directives: {// 拖拽drag(el) {el.onmousedown function (e) {let x e.pageX - el.offsetLeftlet y e.pageY - el.offsetTopdocument.onmousemove function (e) {el.style.left e.pag…

【C++】C++ STL标准模板库知识点总结(秋招篇)

文章目录 前言STL的六大组件是&#xff1f;容器(container) 算法(algorithm) 迭代器(iterator) 三者的关系&#xff1f;容器分为几种&#xff1f;分别有哪些&#xff1f;关联性容器和非关联性容器有什么区别&#xff1f;Vector容器是怎么调整大小的&#xff1f;&#xff08;内存…

【MySQL】内置函数

目录 一、日期函数 1、获得年月日 2、获得时分秒 3、获得时间戳 4、在日期的基础上加日期 5、在日期的基础上减去时间 6、计算两个日期之间相差多少天 7、案例 二、字符串函数 1、获取emp表的ename列的字符集 2、要求显示exam_result表中的信息 3、求学生表中学生姓…

短视频矩阵源码/系统搭建/源码

一、短视频矩阵系统开发需要具备以下能力 短视频技术能力&#xff1a;开发人员应具备短视频相关技术能力&#xff0c;如视频编解码、视频流媒体传输等。 大数据存储和处理能力&#xff1a;短视频矩阵系统需要处理大量的视频数据&#xff0c;因此需要具备大数据存储和处理的能力…

传统商超苦战即时零售,或沦为炮灰

眼下&#xff0c;在美团闪购、京东到家、饿了么、淘宝买菜/淘鲜达、盒马&#xff0c;还有朴朴超市、叮咚买菜等一众类超市App或者平台的绝情裹挟下&#xff0c;包含沃尔玛、家乐福、永辉、大润发、联华、华润万家、步步高、中百等等这些传统商超企业巨头&#xff0c;正过得越来…

JAVA面试总结-Redis篇章(六)——数据过期策略

Java面试总结-Redis篇章&#xff08;六&#xff09;——数据过期策略 Redis数据删除策略——惰性删除Redis数据删除策略——定期删除 Redis数据删除策略——惰性删除 Redis数据删除策略——定期删除