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

这篇具有很好参考价值的文章主要介绍了【C++】特殊类的设计 | 类型转换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 特殊类的设计

单例模式

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


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

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

饿汉模式

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

【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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

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


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


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

【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

使用print函数打印数据


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


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

【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

设置私有锁


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

由于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函数时创建)

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


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


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

【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


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

【C++】特殊类的设计 | 类型转换,C++,c++,开发语言
具体代码
//懒汉模式
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语言有隐式类型转换 和显式类型转换

【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)

【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

把int类型转化为double类型

reinterpret_cast

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

【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

把int类型转化为 int*类型

const_cast

去掉const属性

【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
父类作为上 ,子类作为下


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


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

【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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


【C++】特殊类的设计 | 类型转换,C++,c++,开发语言

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

注意:
dynamic_cast只能用于父类含有虚函数的类
文章来源地址https://www.toymoban.com/news/detail-609845.html

到了这里,关于【C++】特殊类的设计 | 类型转换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • C++特殊类设计及类型转换

    目录 一、特殊类的设计 1.不能被拷贝的类 2.只能在堆区构建对象的类 3.只能在栈区构建对象的类 4.不能被继承的类 二、单例模式 1.饿汉模式 2.懒汉模式 3.线程安全 4.单例的释放 三、C++类型转换 1.C语言的类型转换 2.static_cast 3.reinterpret_cast 4.const_cast 5.dynamic_cast 6.总结 特殊类就

    2024年02月17日
    浏览(44)
  • 【C++】特殊类设计+单例模式+类型转换

    需要云服务器等云产品来学习Linux的同学可以移步/--腾讯云--/--阿里云--/--华为云--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。   目录 一、设计一个类,不能被拷贝 1、C++98 2、C++11 二、设计一个类,只能在堆上创建对象 1、将构造设为私有 2、将析构设为

    2024年02月06日
    浏览(54)
  • c++学习之特殊类设计与类型转换

    方法:c++98,通过私有且只申明不实现拷贝构造与赋值函数,从而实现该类不能被拷贝。c++11引入delete后,可以使构造构造与赋值函数等于delete。效果也是无法被拷贝。 方法一,析构私有化 方法二,构造私有化 方法一: 还是构造私有化,但是注意拷贝构造,我们拷贝

    2024年01月20日
    浏览(46)
  • 【C++】特殊类设计+类型转换+IO流

    🌇个人主页:平凡的小苏 📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风翻盘 。 🛸 C++专栏 : C++内功修炼基地 家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真

    2024年02月05日
    浏览(45)
  • 【C++】特殊类的设计

    💕 C++98方式: 在C++11之前,想要一个一个类不被拷贝,只有将 拷贝构造函数 定义为私有,这样在类外就不能调用拷贝构造函数来构造对象了。但是在类内还是可以调用拷贝构造函数来构造对象。 所以正确的做法是 将拷贝构造函数定义为私有,同时拷贝构造函数只声明,不

    2024年02月07日
    浏览(45)
  • C++进阶 特殊类的设计

    本篇博客介绍:介绍几种特殊的类 我们的拷贝只会发生在两个场景当中 拷贝构造函数 赋值运算符重载 所以说我们只需要让类失去 或者说不能使用这两个函数即可 这里有两个解决方案 在C++98中 我们将拷贝构造函数只声明不定义 并且将其访问权限设置为私有即可 原因如下

    2024年02月12日
    浏览(40)
  • C++之特殊类的设计

    目录 一、单例模式 1、设计模式 2、单例模式 1、饿汉模式 2、懒汉模式 3、单例对象的释放问题 二、设计一个不能被拷贝的类 三、设计一个只能在堆上创建对象的类 四、设计一个只能在栈上创建对象的类 五、设计一个不能被继承的类 概念: 设计模式(Design Pattern)是一套被

    2024年02月08日
    浏览(44)
  • 【C++高阶(八)】单例模式&特殊类的设计

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C++从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C++   🔝🔝 在实际场景中,总会遇见一些特殊情况, 比如设计一个类,只能在堆上开辟空间, 亦或者是设计一个类只能实例化一个对象 在实际需求的场景

    2024年02月04日
    浏览(47)
  • 【C++】异常+智能指针+特殊类和类型转换

    上天可能觉得我太孤独,派你来和我一起对抗虚无。 1. C语言传统处理错误的方式无非就是返回错误码或者直接是终止运行的程序。例如通过assert来断言,但assert会直接终止程序,用户对于这样的处理方式是难以接受的,比如用户误操作了一下,那app直接就终止退出了吗?这

    2024年02月08日
    浏览(51)
  • 【C++】特殊类的设计(只在堆、栈创建对象,单例对象)

    🌏博客主页: 主页 🔖系列专栏: C++ ❤️感谢大家点赞👍收藏⭐评论✍️ 😍期待与大家一起进步! 实现方式: 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建 实现方法:

    2024年02月06日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包