[C++]类型转换

一、C语言中的类型转换

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

C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。
1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
2. 显式类型转化:需要用户自己处理

class A
{
public://explicit A(int a)A(int a):_a(a){}
private:int _a;
};class B
{
public:B(const A& a){}
private://...
};int main()
{int i = 1;// 隐式类型转换double d = i;printf("%d, %.2f\n", i, d);//单参数的构造函数支持隐式类型转换(加上explicit就不支持了)A aa1 = 1;B bb1 = aa1;//自定义类型转换,构造一个临时对象然后进行拷贝构造,编译器优化成直接构造int* p = &i;// 显示的强制类型转换int address = (int)p;printf("%p, %d\n", p, address);return 0;
}

缺陷:
转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换

二、 为什么C++需要四种类型转换

C风格的转换格式很简单,但是有不少缺点的:
1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
2. 显式类型转换将所有情况混合在一起,代码不够清晰

下面来看一下c风格转换失败的例子:
1. 不是相近类型的形式不能进行显示转换

void test()
{vector<int> v;string s;v = (vector<int>)s;
}

编译报错:

2. 隐式类型转换的坑

while循环中,用end和pos作为判断条件,然而pos是size_t类型,当pos为0时,end小于pos后为负数,end与pos比较时又会转换为size_t类型进行比较,所以end会一直大于pos,造成死循环。

3. 对const变量进行转换:

int main()
{const int n = 10;//n = 11;// 转换有安全隐患的int* p = (int*)&n;(*p)++;cout << n << endl;cout << *p << endl;cout << p << endl;return 0;
}

运行结果:

我们发现,p指向的确实是n的地址,但是p对n进行修改后,打印出来的还是10,而p解引用的值是11。

我们再来监视窗口查看:

我们发现监视窗口中n的值是11,那为什么打印出来的是10呢。

这是因为编译器认为对const变量进行类型转换是有安全隐患的,所以编译器将const变量的开始的值存到寄存器中,打印的时候直接在寄存器中去取,或者直接用类似typedef进行常量替换,所以打印出来的是10,而监视串口查看的是内存中的值,这是确实发生了修改的。

那我们有什么办法将内存中的值打印出来呢?

答案是用volatile关键字。

int main()
{// volatile 修饰的变量,每次都要去内存取volatile const int n = 10;//n = 11;// 转换有安全隐患的int* p = (int*)&n;(*p)++;cout << n << endl;cout << *p << endl;cout << &p << endl;cout << p << endl;return 0;
}

运行结果:

volatile 修饰的变量,每次都要去内存取,所以我们可以看到这次运行的结果都是11了。

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

三、 C++强制类型转换

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:
static_cast、reinterpret_cast、const_cast、dynamic_cast

3.1 static_cast

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用
static_cast,但它不能用于两个不相关的类型进行转换

int main()
{// 相关类型/相近类型double d = 12.34;int a = static_cast<int>(d);cout << a << endl;
}

3.2 reinterpret_cast

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

int main()
{double d = 12.34;int a = static_cast<int>(d);cout << a << endl;// 这里使用static_cast会报错,应该使用reinterpret_cast//int *p = static_cast<int*>(a);int* p = reinterpret_cast<int*>(a);return 0;
}

3.3 const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值

注意这里要加上volatile 关键字才能输出修改后的数字

int main()
{// 去掉const属性volatile const int n = 10;int* p2 = const_cast<int*>(&n);*p2 = 3;cout << n << endl;
}

3.4 dynamic_cast

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


向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用->子类指针/引用(dynamic_cast转型是安全的)
注意:

  1. dynamic_cast只能用于父类含有虚函数的类(虚函数的类有虚表,可以认为编译器在虚表中做了一个记号,通过这个记号判断是父类对象指针/引用是指向父类还是指向子类)
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
class A
{
public:virtual void f() {}int _x = 0;
};class B : public A
{
public:int _y = 0;
};void fun(A* pa)
{// pa是指向子类对象B的,转换可以成功,正常返回地址// pa是指向父类对象A的,转换失败,返回空指针B* pb = dynamic_cast<B*>(pa);if (pb){cout << "转换成功" << endl;pb->_x++;pb->_y++;}else{cout << "转换失败" << endl;}
}int main()
{A aa;fun(&aa);B bb;fun(&bb);return 0;
}

运行结果:

可以看到aa是指向父类对象A的,转换失败,返回空指针;bb是指向子类对象B的,转换可以成功,正常返回地址。

注意:
强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是
否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用
域,以减少发生错误的机会。强烈建议:避免使用强制类型转换

四、RTTI(了解)

RTTI:Run-time Type identification的简称,即:运行时类型识别。
C++通过以下方式来支持RTTI:
1. typeid运算符
2. dynamic_cast运算符
3. decltype

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

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

相关文章

VMware克隆虚拟机

VMware克隆虚拟机&#xff1a; https://blog.csdn.net/wisdom_futrue/article/details/128553427

python astra相机驱动问题

报错问题&#xff1a; openni.utils.OpenNIError: (OniStatus.ONI_STATUS_ERROR, bDeviceOpen using default: no devices found, None) 解决办法&#xff1a; 1、从sdk中拷贝文件 2、修改openni源码 3、执行测试程序 from openni import openni2 import numpy as np impor…

python中多行注释与取消注释

在小白学习python编程的过程中&#xff0c;我们经常会发现很多同学们喜欢问的一个问题&#xff1a; 怎么多行注释呢&#xff1f; 怎么取消多行注释呢&#xff1f; 以上种种问题我相信来到这里都会得到相应答案 那我们接下来开始吧&#xff01; 文章目录 单行注释多行注释取消多…

day4:Node.js 核心库

day4:Node.js 核心库 文章目录 day4:Node.js 核心库常用工具模块util 模块Moment 模块Lodash 模块web模块文件模块path 模块常用工具模块 Node.js有许多常用的工具,以下是一些常见的: util: 是一个Node.js 核心模块,提供常用函数的集合,用于弥补核心 JavaScript 的功能…

docker运行redis镜像

很多项目会用到redis作为缓存用到项目中&#xff0c;鉴于刚了解过docker&#xff0c;今天这里用docker运行redis镜像&#xff0c;这样下载&#xff0c;安装运行&#xff0c;或者是使用后的删除都会干净&#xff0c;简单。 好了&#xff0c;第一步是先拉取镜像&#xff0c;使用d…

adb 获取 Android 设备中已安装的 apk 文件

前言 今天发现手机上一个应用在应用商店已经搜索不到了&#xff0c;想把其推荐给朋友使用&#xff0c;发现不知道从哪里找原始的 apk 安装文件&#xff0c;记录一下。 如何提取 apk 两种方法 MT管理器导出 可以使用 MT管理器(Android 平台逆向神器)&#xff0c;它有个 安装…

centos 7.9 安装sshpass

1.作用 sshpass是一个用于非交互式SSH密码验证的实用程序。它可以用于自动输入密码以进行SSH登录&#xff0c;从而简化了自动化脚本和批处理作业中的SSH连接过程。 sshpass命令可以与ssh命令一起使用&#xff0c;通过在命令行中提供密码参数来执行远程命令。以下是一个示例命…

openGauss学习笔记-102 openGauss 数据库管理-管理数据库安全-客户端接入之查看数据库连接数

文章目录 openGauss学习笔记-102 openGauss 数据库管理-管理数据库安全-客户端接入之查看数据库连接数102.1 背景信息102.2 操作步骤 openGauss学习笔记-102 openGauss 数据库管理-管理数据库安全-客户端接入之查看数据库连接数 102.1 背景信息 当用户连接数达到上限后&#…

查看Linux系统查看CPU架构和系统版本信息

查看发行版本&#xff08;对内核进行了包装的&#xff09; 国产麒麟 cetcet1:~$ cat /etc/.kyinfo [dist] nameKylin milestoneDesktop-V10-SP1-General-Release-2203 archarm64 betaFalse time2022-05-13 16:25:37 dist_idKylin-Desktop-V10-SP1-General-Release-2203-arm64…

TCP实战:即时通信-端口转发

1、即时通信是什么含义&#xff0c;要实现怎么样的设计&#xff1f; 即时通信&#xff0c;是指一个客户端的消息发出去&#xff0c;其他客户端可以接收到即时通信需要进行端口转发的设计思想服务端需要把在线的Socket管道存储起来一旦收到一个消息要推送给其他管道 服务端 pac…

vmware安装 Rocky9(自定义分区安装)

一、下载镜像 访问官网&#xff0c;下载dvd的镜像 Download Rocky | Rocky Linuxhttps://rockylinux.org/download 二、新建vmware虚拟机 1、vmware尽量选择vmware17 2、下一步 3、稍后安装 4、选择系统类型&#xff1a;red hat9 5、自定义安装位置 6、根据电脑配置&#…

24. Kernel 4.19环境下,Cilium网络仍然需要使用iptables

在设计这套容器集群服务时,我从原来的k3s架构中分离出一个问题,那就是容器网络插件应该选择哪个。因为我设计的目标是给服务器领域使用的容器引擎,所以我就不需要考虑太多边缘IOT设备的情况,直接拉满技能找了cilium。cilium借助内核ebpf技术的出现,让我看到了网络性能更好…

【数据结构】模拟实现LinkedList

LinkedList是双向链表结构可以适用于任意插入场景下的插入和删除&#xff0c;效率较高&#xff0c;时间复杂度为O(1)。 模拟实现 public class MyLinkedList {static class ListNode{private int val;//值域private ListNode prev;//前驱private ListNode next;//后继public …

LeetCode:2316. 统计无向图中无法互相到达点对数(C++)

目录 2316. 统计无向图中无法互相到达点对数 题目描述&#xff1a; 实现代码与解析&#xff1a; 并查集 原理思路&#xff1a; 2316. 统计无向图中无法互相到达点对数 题目描述&#xff1a; 给你一个整数 n &#xff0c;表示一张 无向图 中有 n 个节点&#xff0c;编号为…

echarts label fomatter a b c d含义

模板变量有 {a}, {b}&#xff0c;{c}&#xff0c;{d}&#xff0c;{e}&#xff0c;分别表示系列名&#xff0c;数据名&#xff0c;数据值等。 在 trigger 为 axis 的时候&#xff0c;会有多个系列的数据&#xff0c;此时可以通过 {a0}, {a1}, {a2} 这种后面加索引的方式表示系列…

AWS Lambda – 函数版本,别名,API网关,CodeDeploy协同

Hello大家好&#xff0c;我们今天继续讨论AWS Lambda的内容。 Lambda函数的版本 Lambda函数的版本和别名是辅助资源&#xff0c;我们可以通过创建这些资源管理函数的部署和调用。 首先&#xff0c;让我们来看一下Lambda 函数版本的概念。您可以使用版本来管理函数的部署。例…

window mysql5.7.27 启用SSL openssl mysql_ssl_rsa_setup

应客户监管部门要求 mysql必须要启用SSL。由于mysql安装在window上&#xff0c;启用过程中遇到了不少的坑&#xff0c;在此记录一下。 安装openssl 如果已经安装过可跳过此步 https://slproweb.com/download/Win64OpenSSL-1_1_1w.msi复制到浏览器下载后安装即可。如果需要其他…

前端数据可视化之【Echarts下载使用】

目录 &#x1f31f;下载&#x1f31f;浏览器引入&#x1f31f;模块化引入 &#x1f31f;使用&#x1f31f;基本使用步骤 &#x1f31f;绘制一个简单的图表&#x1f31f;写在最后 &#x1f31f;下载 &#x1f31f;浏览器引入 官网下载界面&#xff1a;官方网站 或 Echarts中文…

Bootstrap的列表组相关知识

目录 01-列表组的相关基础知识02-一个简单的列表组示例03-激活或禁用列表组的一行或多行04-设置列表项的颜色05-给列表项添加徽章 01-列表组的相关基础知识 Bootstrap的list-group是一个用于创建列表组件的CSS类&#xff0c;通常用于显示一个项目列表&#xff0c;如导航菜单或…

迁移kubelet、docker和containerd工作目录

文章目录 问题背景迁移Docker停止 Docker 服务修改配置移动文件重新启动 Docker 服务 containerd停止服务修改配置移动文件重新启动服务 kubelet&#xff08;遇到问题待解决&#xff09;停止服务修改配置移动文件&#xff08;遇到问题待解决&#xff09;重新启动服务 使用的版本…