【C++进阶之路】类型转换

news2025/3/12 19:21:22

文章目录

  • 类型转换
    • 1.C语言的类型转换
      • 1.1整形提升
      • 1.2算术转换
      • 1.3强制类型转换
    • 2.C++类型转换
      • 2.1static_cast
      • 2.2reinterpret_cast
      • 2.3const_cast
      • 2.3dynamic_cast
  • 总结

类型转换

1.C语言的类型转换

1.1整形提升

在写顺序表的插入函数时,我们的接口实现是这样的:

void intsert(Seq* s,size_t pos,int val)
{
	int end = s->size - 1;
	while(end >= pos)
	{
		s->arr[end + 1] = s->arr[end];
		end--;
	}
	//此时我们已经写出了一个bug
}

当插入的位置为0时,由于pos位置为size_t类型的,此时会导致end在比较时会发生整形提升,自动的转换为unsigned int 类型进行比较,由于unsigned int 类型大于等于0,因此到0之后再减减进行比较是不会停止的。

  • 截断
int main()
{
	int a = 257;
	char b = a;
	return 0;
}
  • 由于存储数据的范围不一样或者说是内存不一样,所以在拷贝内存的数据时,会发生只拷贝部分内存的现象,这种现象我们称之为截断。

1.2算术转换

#include<stdio.h>
int main()
{
	int a = 2;
	double b = a;//也叫隐式类型转换
	float c = (float) a;//也叫显示类型转换
	printf("%lf", b);
	return 0;
}

从内存的角度进行理解,由于int和double的存储方式不一样,因此需要按照某种规则进行转换,而不是直接的将内存进行拷贝。

1.3强制类型转换


int main()
{
	int a = 2;
	double b = a;

	int* ptr = (int*)a;
	int* ptr1 = (int*)&b;
	//注:int* ptr2 = (int*)b;——类型转换无效,跨度太大了。
	return 0;
}
  • 指针和整形是两种用途完全不同的类型,这两种几乎用途不想关的类型,可以通过强转,而关联起来,除此之外不同类型的指针指向的类型不同,也可以通过强转而改变类型,本质上是改变计算机从内存解释数据的角度。

C语言的类型转换,从总体上看是比较容易出错的,也不太规范,因为从我们举的第一个例子看是很容易出错的,而且即使所有的C类型的显示转换的形式是一样的,但还是有本质区别的。

2.C++类型转换

2.1static_cast

  • 用于编译器支持的隐式类型转换。
  • 非多态类型的转换(向下转换不保证安全性)。
  • 空指针的转换以及任意指针转void*
  • 注意:转换时,不能丢掉const或者其他类型限定符。
class A
{

};
class  B : public A
{
public:
	void func()
	{
		cout << "B:func()" << endl;
	}
private:
	int _a = 0;
};
//class 默认私有继承,struct默认公有继承。
int main()
{
	int n1 = 0;
	float f1 = 0.0f;
	double d1 = 0.0;
	char c = 'a';

	//1.用于编译器支持的隐式类型转换。
	n1 = static_cast<int>(f1);
	n1 = static_cast<int>(d1);
	n1 = static_cast<int>(c);
	//2.非多态类型的转化。
	A a;
	B b;
	A& ra = static_cast<A&>(b);//向上转换是安全的。
	B& rb = static_cast<B&>(a);//向下转换是不安全的。

	//3.空指针转换为任何类型的指针
	A* a_ptr = static_cast<A*>(nullptr);
	int* i_ptr = static_cast<int*>(nullptr);

	//4.所有指针转换为void*类型的
	void* vptr1 = static_cast<void*>(a_ptr);
	vptr1 = static_cast<void*>(i_ptr);

	//5.无法丢掉常量或其他类型限定符
	volatile const int n3 = 0;//说明:volatile每次从内存中取数据。
	volatile const int& rn3 = static_cast<volatile const int&>(n3);

	return 0;
}

2.2reinterpret_cast

  • 只适用于不安全的类型之间的转换。
class B
{};
class A
{};
int main()
{
	int n1 = 0;
	float f1 = 0.0f;
	double d1 = 0.0;
	char c = 'a';

	//1.只能用于适合强转(不安全的转换)的类型,不能用于相关编译器支持的隐式转换(安全)的类型转换。
	//如:不同类型的指针转换或者不同类型的引用,或者其他类型转指针的转换
	int& r = reinterpret_cast<int&>(f1);
	int* p = reinterpret_cast<int*>(&f1);
	B b;
	A a;
	A* a_ptr = &a;
	B* b_ptr = reinterpret_cast<B*>(a_ptr);
	//2.不能用于类之间的转换
	//B b = reinterpret_cast<B>(A());
	
	//3.无法丢掉常量或者其他类型限定符 
	const int i_a = 0;
	//int& ra = reinterpret_cast<int&>(i_a);
	return 0;
}

2.3const_cast

  • 最为关键的作用就是去掉const属性,只能调节类型限定符,不能修改类型。
int main()
{
	//去掉const属性
	const int a = 0;
	int& ra = const_cast<int&>(a);
	ra = 1;
	//指针可以去掉两个const
	const int* const p = &a;
	int*& p1 = const_cast<int*&>(p);
	return 0;
}

2.3dynamic_cast

  • 主要功能实现多态类型的向下转换
  1. 指针类型如果转化失败,则为空指针。
  2. 引用如果转换失败,则直接抛异常——Bad dynamic_cast!

细节:必须为多态类型,因为是否能转化成功要看虚表

class A
{
	virtual void func()
	{}
};
class B : public A
{};
void func(A* ptr)
{
	B* ptr_b = dynamic_cast<B*>(ptr);//必须是多态类型的,即有虚表。
	if (ptr_b == nullptr)
	{
		cout << "转换失败" << endl;
	}
	else
	{
		cout << "转换成功" << endl;
	}
}
void func(A& ra)
{
	B& rb = dynamic_cast<B&>(ra);
	cout << "转换成功" << endl;
}
int main()
{
	A* ptr_a = new A;
	B* ptr_b = new B;

	func(ptr_a);
	func(ptr_b);
	try
	{
		func(*ptr_b);
		func(*ptr_a);
	}
	catch (const exception&  e)
	{
		cout << e.what() << endl;
	}
	return 0;
}
  • 那dynamic是如何进行实现的呢?

  • 基本原理:RTTI,Run-time Type identification的简称,即:运行时类型识别。

  • 实现方式: 1. typeid运算符 2. dynamic_cast运算符 3. decltype

模型图:
在这里插入图片描述

每个类都保存有自己的类型信息(具体是保存在虚表中),并通过继承方式连接起来,再检查是否为安全的类型转换时,通过向上查找,看是否存在要转化的对象,如果有便转换成对象,如果没有便抛异常或者进行报错。

  • 查找规则:当使用 dynamic_cast 对指针进行类型转换时,会先找到该指针指向的对象,再根据对象找到当前类(指针指向的对象所属的类)的类型信息,并从此节点开始沿着继承链向上遍历(注意是向上),如果找到了要转化的目标类型,那么说明这种转换是安全的,就能够转换成功,如果没有找到要转换的目标类型,那么说明这种转换存在较大的风险,就不能转换。
  • 作用对象:注意dynamic_cast转换符只能用于含有虚函数的类。

总结

 今天的分享就到此结束了,我是舜华,期待与你的下一次相遇!

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

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

相关文章

Confluence 自定义展示页面

1. 概述 Confluence 作为知识库可通过JS脚本方式&#xff0c;根据登录用户或用户组进行前端页面的自定义 2. 实现方式 Confluence →管理→自定义HTML 嵌入对应JS脚本&#xff0c;示例如下 <script type"text/javascript">jQuery(#footer).html(<div>…

UE5 Python脚本自动化Sequence Key帧

前言 码上1024了&#xff0c;给大家分享一个UE5的脚本小功能&#xff0c;UE5中Sequence动态Key功能&#xff0c;这样我们就可以根据我们的数据动态更新了&#xff0c;非常实用&#xff0c;适合刚入门或者小白&#xff0c;接下来我就把整个过程分享给大家。 过程 新建一个工程…

E049-论坛漏洞分析及利用-针对bwapp进行web渗透测试的探索

课程名称&#xff1a; E049-论坛漏洞分析及利用-针对bwapp进行web渗透测试的探索 课程分类&#xff1a; 论坛漏洞分析及利用 --------------------------------------------------------------------------------------------------------------------------------- 实验等…

用一段爬虫代码爬取高音质音频示例

以下是一个使用Reachability库和Objective-C编写的爬虫程序&#xff0c;用于爬取高音质的免费音频。通过https://www.duoip.cn/get_proxy的代码示例完美抓取数据。 #import <Foundation/Foundation.h> #import <Reachability/Reachability.h>interface AudioCrawle…

vue3学习(八)--- 组件相关

文章目录 全局组件批量注册全局组件 局部组件递归组件组件定义名称方式1.增加一个script 通过 export 添加name2.直接使用文件名当组件名3.使用插件 unplugin-vue-define-options 动态组件异步组件 一个 Vue 组件在使用前需要先被“注册”&#xff0c;这样 Vue 才能在渲染模板时…

从实时数据库转战时序数据库,他陪伴 TDengine 从 1.0 走到 3.0

关于采访嘉宾 在关胜亮的学生时代&#xff0c;“神童”这个称号如影随形&#xff0c;很多人初听时会觉得这个称谓略显夸张&#xff0c;有些人还会认为这是不是就是一种调侃&#xff0c;但是如果你听说过他的经历&#xff0c;就会理解这一称号的意义所在了。 受到教师母亲的影…

Mobpush厂商通道回执配置指南

为了帮助客户追踪和分析推送效果&#xff0c;Mobpush为APP开发者提供了用户收到推送后行为特征的数据分析&#xff0c;但由于用户使用的设备存在较大差异&#xff0c;不同厂商通道之间配置存在较大差异&#xff0c;不同的厂商通道对送达、展示和点击数据回执的支持程度各不相同…

汽车智能制造中的RFID技术在供应链生产管理中的应用

行业背景 汽车零部件工业是汽车工业中至关重要的一部分&#xff0c;对于汽车工业的长期稳定发展起着基础性的作用&#xff0c;近年来&#xff0c;汽车配件配套市场规模达到了2000亿元&#xff0c;维修市场达到了600亿元&#xff0c;随着汽车国产化的推进&#xff0c;汽车零部件…

机器学习-ROC曲线:技术解析与实战应用

目录 一、引言ROC曲线简介 二、ROC曲线的历史背景二战雷达信号检测在医学和机器学习中的应用横跨多个领域的普及 三、数学基础True Positive Rate&#xff08;TPR&#xff09;与False Positive Rate&#xff08;FPR&#xff09;True Positive Rate&#xff08;TPR&#xff09;F…

DNS域名解析与Web服务

一、DNS 域名解析 1、概念&#xff1a; (1) DNS&#xff1a; DNS&#xff08;Domain Name System&#xff09;是一种用于将可读的域名&#xff08;如www.baidu.com&#xff09;转换为计算机可理解的IP地址&#xff08;如192.168.1.1&#xff09;的分布式命名系统&#xff0c…

uniapp(uncloud) 使用生态开发接口详情5(云公共模块)

1.uniCloud官网 云对象中云公共模块: 网站: https://uniapp.dcloud.net.cn/uniCloud/cf-common.html // 官网介绍 cloudfunctions├─common // 云函数公用模块目录| └─hello-common // 云函数公用模块| ├─package.json| └─index.js // 公用模块代码&#xff0…

BaiChuan2保姆级微调范例

前方干货预警&#xff1a;这可能是你能够找到的&#xff0c;最容易理解&#xff0c;最容易跑通的&#xff0c;适用于各种开源LLM模型的&#xff0c;同时支持多轮和单轮对话数据集的大模型高效微调范例。 我们构造了一个修改大模型自我认知的3轮对话的玩具数据集&#xff0c;使用…

Scrapy设置代理IP方法(超详细)

Scrapy是一个灵活且功能强大的网络爬虫框架&#xff0c;用于快速、高效地提取数据和爬取网页。在某些情况下&#xff0c;我们可能需要使用代理IP来应对网站的反爬机制、突破地理限制或保护爬虫的隐私。下面将介绍在Scrapy中设置代理IP的方法&#xff0c;以帮助您更好地应对这些…

PAM从入门到精通(六)

接前一篇文章&#xff1a;PAM从入门到精通&#xff08;五&#xff09; 本文参考&#xff1a; 《The Linux-PAM Application Developers Guide》 先再来重温一下PAM系统架构&#xff1a; 更加形象的形式&#xff1a; 五、主要函数详解 4. pam_get_item 概述&#xff1a; 获取…

YUV图片常见格式

YUV图像 1个亮度量Y2个色度量(UV) 兼容黑白电视 可以通过降低色度的采样率而不会对图像质量影响太大的操作&#xff0c;降低视频传输带宽 有很多格式&#xff0c;所以渲染的时候一定要写对&#xff0c;不然会有很多问题&#xff0c;比如花屏、绿屏 打包格式 一个像素点一…

SRE 的黄昏,平台工程的初晨

船停在港湾是最安全的&#xff0c;但这不是造船的目的 完成使命的 SRE 过去 10 年&#xff0c;SRE 完成了体系化保障系统稳定性的使命。但在这个过程中&#xff0c;SRE 也逐渐变成了庞大的组织。而 SRE 本身的定位是保障系统稳定性&#xff0c;许多时候会因为担心稳定性而减缓…

线性代数-Python-01:向量的基本运算 -手写Vector -学习numpy的基本用法

文章目录 代码目录结构Vector.py_globals.pymain_vector.pymain_numpy_vector.py 一、创建属于自己的向量1.1 在控制台测试__repr__和__str__方法1.2 创建实例测试代码 二、向量的基本运算2.1 加法2.2 数量乘法2.3 向量运算的基本性质2.4 零向量2.5 向量的长度2.6 单位向量2.7 …

Linux上Docker的安装以及作为非运维人员应当掌握哪些Docker命令

目录 前言 1、安装步骤 2、理解镜像和容器究竟是什么意思 2.1、为什么我们要知道什么是镜像&#xff0c;什么是容器&#xff1f; 2.2、什么是镜像&#xff1f; 2.3、什么是容器&#xff1f; 2.4、Docker在做什么&#xff1f; 2.5、什么是镜像仓库&#xff1f; 2、Dock…

ArkTS开发实践

声明式UI基本概念 应用界面是由一个个页面组成&#xff0c;ArkTS是由ArkUI框架提供&#xff0c;用于以声明式开发范式开发界面的语言。 声明式UI构建页面的过程&#xff0c;其实是组合组件的过程&#xff0c;声明式UI的思想&#xff0c;主要体现在两个方面&#xff1a; 描述U…

基于PHP的毕业生招聘管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…