【C++】一文掌握C++的四种类型转换 --- static_cast、reinterpret_cast、const_cast、dynamic_cast

news2024/11/14 2:58:24

在这里插入图片描述

当面对两个选择时,抛硬币总能奏效。
并不是因为它总能给出对的答案,
而是在你把它抛在空中的那一秒里。
你突然就知道,你希望的结果是什么了。
--- 曾小贤 《爱情公寓》---

一文掌握C++的四种类型转换

  • 1 C++中的类型
  • 2 类型转换
  • 3 四种类型转换
    • 3.1 static_cast 静态转换
    • 3.2 reinterpret_cast 重新解释
    • 3.3 const_cast 去常转换
    • 3.4 dynamic_cast 动态转换
    • 3.5 RTTI(了解)
  • 4 使用建议

1 C++中的类型

C++中类型分为两种:内置类型和自定义类型。内置类型中分为算术类型和空类型。其中算术类型包含字符,整型,布尔值和浮点数。空类型不对应具体的值,仅用于一些特殊的场合,例如最常见的是,当函数不返回任何值时使用空类型作为返回类型。

类型含义尺寸
bool布尔类型只有一位 1表示True 0表示False 有数据表示为True,0表示为False
char字符8 位
wchar_t宽字符16位
char16_tUnicode字符16位
char32_tUnicode字符32位
short短整型C++要求short类型不少于16位 ,一般为16位
int整型C++要求int类型至少与short类型一样长,一般为32位
long长整型C++要求long至少为32位,且至少与int一样长 , 一般为32位
long long长整型C++要求long long至少为64位,且至少与long一样长,一般为64位
float单精度浮点型C++要求至少为32位。后缀F or f
double双精度浮点型C++要求至少为48位,且不少于float
long double扩展精度浮点型C++要求为80,96,128位,至少和double类型位数一样多

对于这些内置类型,在使用时将一个类型赋值给另一个类型或者是在进行运算时,如果两个类型有关联就会发生隐式类型转换,这种转换不需要程序员介入,是自动执行的,这种转换是有可能造成数据丢失的!

2 类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。

  1. 隐式类型转化:编译器在编译阶段自动进行,能转就转(有关联才能转),不能转就编译失败。整型之间,浮点数和整型之间
  2. 显式类型转化(强制类型转换):需要用户自己处理,各类指针是可以显式类型转换的!

在C++中同样支持C语言风格的类型转换,并且新增了内置类型向自定义类型的转换和自定义类型向内置类型的转换!
我们来写一个类来看看:


class A
{
public:
	//explicit A(int a1) 这样不支持隐式类型转换!
	A(int a1)
		:_a1(a1)
	{}
private:
	int _a1;
	int _a2;
};
int main()
{
	A aa1 = 1;
	return 0;
}

像这样的单参数构造函数的类支持隐式类型转换!多参数的构造函数就需要使用{ } 来进行列表初始化,才可以做到类型转换!
如果不希望该类进行隐式类型转换,可以使用explicit关键字进行修饰,这样就不支持内置类型向自定义类型的隐式类型转换了!

在来看自定义类型如何向内置类型进行转换呢?C++通过了一个十分直接的方法,想转什么类型就operator重载什么类型:

class A
{
public:
	//explicit A(int a1) 这样不支持隐式类型转换!
	A(int a1)
		:_a1(a1)
	{}
	operator int()
	{
		return _a1 + _a2;
	}
private:
	int _a1;
	int _a2;
};

很简单的操作逻辑,这就是C++支持的自定义类型向内置类型的转换,这个不太常用,只要是在IO流中的对象中会有operator bool()来支持进行布尔的判断!

自定义类型之间的类型转换可以通过拷贝构造来进行!

3 四种类型转换

C风格的转换格式很简单,但是有不少缺点的:

  1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
  2. 显式类型转换将所有情况混合在一起,代码不够清晰

因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格:

  1. 隐式类型转换(静态转换):static_cast
  2. 强制类型转换(重新解释):reinterpret_cast
  3. 去常转换:const_cast
  4. 动态转换:dynamic_cast

3.1 static_cast 静态转换

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换。也就是说,只要是C风格的类型转换,可以都套上static_cast!

任何具有明确定义的类型转换,只有是不包括底层const,都可以使用static_cast!
在这里插入图片描述
注意:隐式类型转换不支持的转换,套上static_cast也不支持!

如果我们将一些需要进行强制类型转换的场景也套上 static_cast,这时就会发生报错了!这保证了不能乱用
对于需要强制类型转换的场景需要使用reinterpret_cast
总结:

  1. static_cast 可以用于基本类型的转换
  2. static_cast 不能用于基本类型指针间的转换(需要强制类型转换)
  3. static_cast可以用于有继承关系类对象之间的转换和类指针之间的转换
    (派生类转换成基类时安全(上行转换),基类转换成派生类时不安全(下行转换))
    在这里插入图片描述

3.2 reinterpret_cast 重新解释

在隐式类型转换不能进行转换时,我们就需要强制类型转换。强制类型转换很有可能会造成运行时的错误!

reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型

3.3 const_cast 去常转换

const_cast 只能改变运算对象的底层const。只有 const_cast 可以做到去常,并且还要配合使用volatie关键字。const_cast最常用的用途就是删除变量的const属性,方便赋值。会将一个稳定的变量变成不稳定的!
在这里插入图片描述

去常操作常常在函数重载中进行使用:比如在类内我们要实习一个功能:比较两个字符串的大小。为了适配常量字符串和非常量字符串,我们需要进行一个函数重载:

const string& func(const string& s1 , const string& s2)
{
	return s1.size() <= s2.size() ? s1  : s2;
}
string& func(string& s1 , string& s2)
{
	return s1.size() <= s2.size() ? s1  : s2;
}

上面的场景是很常见的,如果遇到函数实现比较复杂的情况,在使用上面的做法就有些冗余了,我们可以在上层对const版本的函数进行一次包装,来适配正常版本:

string& func(string& s1 , string& s2)
{
	auto &r = func(static_cast<const string&>(s1) , static_cast<const string&> (s2));
	return const_cast<string&>(r);
}

这样就简单通过一个const版本的函数,通过去常操作实现了非const版本的函数!这是十分安全的操作!

3.4 dynamic_cast 动态转换

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转换:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转换:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)

学习过继承之后,我们知道派生类内部是包含一个基类,可以通过切片的方式来转换成基类!甚至不需要产生临时对象!这是天然支持的!但是对于基类转换为子类就有点复杂了!

void func(A* pa)
{
	B* pb = (B*)pa;
}

对于这样一个函数,基类指针会强制类型转换为子类指针,当pa指针本来就是指向的是一个B对象,在转换回去,没有问题。但是当pa指针指向的是A对象,那么强行转换会造成越界的问题!在读取时会造成崩溃!

为了解决这个问题,可以使用 dynamic_cast :

void func(A* pa)
{
	B* pb = dynamic_cast<B*>(pa);
	if (pb)
	{
		cout << pb << endl;
		pb->_b1++;
	}
	else
	{
		cout << "转换失败!" << endl;
	}
}

如果pa指针指向的是B对象,转换成功!
如果pa指针指向的是A对象,转换失败!返回空!

总结:

  1. dynamic_cast只能用于父类含有虚函数的类
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0

3.5 RTTI(了解)

RTTI:Run-time Type identification的简称,即:运行时类型识别。
C++通过以下方式来支持RTTI:

  1. typeid 运算符
  2. dynamic_cast 运算符
  3. decltype

4 使用建议

强制类型转换干扰了正常的类型检查,因此我们强烈建议程序员避免使用强制类型转换。这个建议对于reinterpret_cast尤其适用,因为此类类型转换总是充满了风险。

在有重载函数的上下文中使用const cast无可厚非,但是在其他情况下使用const cast也就意味着程序存在某种设计缺陷。其他强制类型转换,比如static_castdynamic_cast,都不应该频繁使用。

每次书写了一条强制类型转换语句,都应该反复斟酌能否以其他方式实现相同的目标就算实在无法避免,也应该尽量限制类型转换值的作用域,并且记录对相关类型的所有假定,这样可以减少错误发生的机会

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

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

相关文章

一次caffeine引起的CPU飙升问题

背景 背景是上游服务接入了博主团队提供的sdk&#xff0c;已经长达3年&#xff0c;运行稳定无异常&#xff0c;随着最近冲业绩&#xff0c;流量越来越大&#xff0c;直至某一天&#xff0c;其中一个接入方&#xff08;流量很大&#xff09;告知CPU在慢慢上升且没有回落的迹象&…

Godot《躲避小兵》实战之创建玩家场景

项目设置完之后&#xff0c;我们就可以开始处理玩家控制的角色。 这里我们将玩家放在一个单独的场景当中&#xff0c;这样做的好处是在游戏的其他部分做出来之前&#xff0c;我们就可以对其进行单独测试。 节点结构 场景是一个节点树结构&#xff0c;因此一个场景需要有一个…

设计模式六大原则之:依赖倒置原则

1. 依赖倒置原则简介 依赖倒置原则(Dependency Inversion Principle, DIP) 是面向对象设计的核心原则之一&#xff0c;由罗伯特马丁(Robert C. Martin)提出&#xff0c;旨在降低类间的依赖度&#xff0c;使之更易于维护和扩展。该原则主张高层模块不应该依赖于底层模块&#x…

江科大/江协科技 STM32学习笔记P23

文章目录 DMA直接存储器存取DMA简介存储器映像DMA框图DMA基本结构存储器到存储器的数据转运ADC扫描模式和DMA配合使用流程 DMA直接存储器存取 DMA简介 DMA进行存储器到存储器的数据转运&#xff0c;比如Flash里的一批数据转运到SRAM里&#xff0c;需要软件触发&#xff0c;使用…

JQuery实现的时间插件源码附注释

HTML页面代码 <!DOCTYPE HTML> <html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta content="width=device-width, initial-scale=1, maximum-scale=1,user-scalable=no;" name="…

【方案】SRM系统整体设计方案(解决方案+实现源码)

一、项目理解 二、总体解决方案概述 三、业务解决方案详述 四、端到端的采购流程管理 1. 采购计划 2. 采购寻源(招投标、询报价、竞价) 3. 合同管理 4. 订单执行与供应商协同 5. 采购分析与评估 五、支撑流程 1. 物资主数据管理 2. 供应商管理 3. 目录管理 4. 评标专家库管理 5…

grom接入Prometheus,grafana

在同级目录下分别创建 docker-compose.yml&#xff0c;与prometheus.yml 配置文件 version: 3.8services:prometheus:image: prom/prometheuscontainer_name: prometheusports:- "9090:9090" # Prometheus Web UI 端口volumes:- ./prometheus.yml:/etc/prometheus…

opencv-python实战项目八:根据颜色抠出图片中感兴趣区域

文章目录 一&#xff0c;简介二&#xff0c;实现方案三、算法实现步骤3.2 处理颜色蒙版&#xff1a;3.3 取出图片中蒙版对应区域 四&#xff0c;整体代码五&#xff0c;效果&#xff1a; 一&#xff0c;简介 本项目旨在开发一个基于OpenCV的图像处理工具&#xff0c;实现根据颜…

商贸城小程序系统开发制作方案

商贸城作为集批发、零售、展示、交流于一体的综合性商业体。通过商贸城小程序系统促进商家与消费者之间的互动&#xff0c;实现线上线下流量的无缝对接。一、用户需求分析 1、顾客需求&#xff1a; 快速查找店铺信息&#xff1b; 在线浏览商品和服务&#xff1b; 实现线上预约、…

【网站项目】SpringBoot675学生心理压力咨询评判

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Vue启动时报异常 ‘error:03000086:digital envelope routines::initialization error‘

问题描述 启动Vue项目时&#xff0c;突发报如下异常&#xff1a; opensslErrorStack: [error:03000086:digital envelope routines::initialization error,error:0308010C:digital envelope routines::unsupported],library: digital envelope routines,reason: unsupported,…

CentOS7下载与安装 即配置网卡

CentOS 7是什么? CentOS7是基于RHEL的企业级Linux操作系统&#xff0c;引入了Systemd、XFS文件系统和Docker支持。它提供了新的软件包、工具和性能调优选项&#xff0c;同时加强了系统安全和稳定性。总的来说&#xff0c;CentOS7是一个稳定、安全、长期支持的操作系统&#xf…

【wiki知识库】09.欢迎页面展示(浏览量统计)SpringBoot部分

&#x1f34a; 编程有易不绕弯&#xff0c;成长之路不孤单&#xff01; 大家好&#xff0c;我是熊哈哈&#xff0c;这个项目从我接手到现在有了两个多月的时间了吧&#xff0c;其实本来我在七月初就做完的吧&#xff0c;但是六月份的时候生病了&#xff0c;在家里休息了一个月的…

【和可被 K 整除的子数组】python刷题记录

R4-前缀和专题 class Solution:def subarraysDivByK(self, nums: List[int], k: int) -> int:ret0# 存储当前位置的上一个位置的前缀和的余数加上当前位置的值对K的余数pre_mod0dictdefaultdict(int)dict[0]1for i in range(len(nums)):pre_mod(pre_modnums[i])%k# 如果能在…

Kubernetes 基础概念介绍

1. 应用部署方式 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其它技术的参与 缺点&#xff1a;不能为应用程序定义资源使用边界&#xff0c;很难合理地分配计算资源&#xff0c;而且程序之间容易产生影…

投票小程序App功能开发源码技术实现

随着移动互联网的快速发展&#xff0c;小程序作为一种轻量级应用&#xff0c;因其无需安装、即用即走的特点&#xff0c;在各类应用场景中迅速普及。投票小程序作为其中的一种&#xff0c;因其便捷性和实用性&#xff0c;广泛应用于各类活动、问卷调查及意见收集中。本文将围绕…

Linux-Shell入门-05

1.Shell的概念 1.1 什么是shell Shell脚本语言是实现Linux/UNIX系统管理及自W动化运维所必备的重要工具&#xff0c; Linux/UNIX系统的底层及基础应用软件的核心大都涉及Shell脚本的内容。Shell是一种编程语言, 它像其它编程语言如: C, Java, Python等一样也有变量/函数/运算符…

上海“创投十九条”明确政府引导基金带动作用,银行如何挖掘投贷联动增长潜力?

发展创业投资是促进科技、产业、金融良性循环的重要举措。为促进创业投资高质量发展&#xff0c;近几个月来&#xff0c;“国创投十七条”“上海创投十九条”等政策陆续发布&#xff0c;明确指出发挥政府引导基金带动作用&#xff0c;进一步加大对战略性新兴产业和未来产业的支…

空指针异常(NullPointerException)以及解决方案

之前我们提到过&#xff0c;在学习数组这一篇章时&#xff0c;有两种运行时异常&#xff0c;可能会反复的出现,首先第一个就是我们之前所讲述的&#xff0c;数组下标越界异常&#xff08;ArrayIndexOutOfBoundsException&#xff09;&#xff0c;如需查看详情&#xff0c;可跳转…

tekton通过ceph挂载node_modules的时候报错failed to execute command: copying dir: symlink

分析&#xff1a; 如果ceph的mountPath和workingDir路径一致的话&#xff0c;就会报错。 解决&#xff1a;node_modules挂载到/workspace下&#xff0c;workingDir的代码mv到/workspace下进行构建。