【C++】C++的类型转换

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:C++学习
🎯长路漫漫浩浩,万事皆有期待

上一篇博客:【C++】C++智能指针

文章目录

  • C语言中的类型转换
  • 为什么C++需要四种类型转换
  • C++强制类型转换
    • static_cast
    • reinterpret_cat
    • const_cast
    • dynamic_cast
    • explicit
  • RTTI
  • 常见面试题
  • 总结:

C语言中的类型转换

C语言和C++都是强类型语言,如果赋值运算符左右两侧变量的类型不同,或形参与实参的类型不匹配,或返回值类型与接收返回值的变量类型不一致,那么就需要进行类型转换。

C语言中有两种形式的类型转换,分别是隐式类型转换和显式类型转换:

隐式类型转换:编译器在编译阶段自动进行,能转就转,不能转就编译失败。
显式类型转换:需要用户自己处理,以(指定类型)变量的方式进行类型转换。

需要注意的是,只有相近类型之间才能发生隐式类型转换,比如int和double表示的都是数值,只不过它们表示的范围和精度不同。而指针类型表示的是地址编号,因此整型和指针类型之间不会进行隐式类型转换,如果需要转换则只能进行显式类型转换。比如:

int main()
{//隐式类型转换int i = 1;double d = i;cout << i << endl;cout << d << endl;//显式类型转换int* p = &i;int address = (int)p;cout << p << endl;cout << address << endl;return 0;
}

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

C风格的转换格式虽然很简单,但也有很多缺点:

隐式类型转换在某些情况下可能会出问题,比如数据精度丢失。
显式类型转换将所有情况混合在一起,转换的可视性比较差。
因此C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符,分别是static_cast、reinterpret_cast、const_cast和dynamic_cast。

C++强制类型转换

static_cast

static_cast用于相近类型之间的转换,编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关类型之间转换。比如:

int main()
{double d = 12.34;int a = static_cast<int>(d);cout << a << endl;int* p = &a;// int address = static_cast<int>(p); //errorreturn 0;
}

reinterpret_cat

reinterpret_cast用于两个不相关类型之间的转换。比如:

int main()
{int a = 10;int* p = &a;int address = reinterpret_cast<int>(p);cout << address << endl;return 0;
}

reinterpret_cast还有一个非常bug的用法,比如在下面的代码中将带参带返回值的函数指针转换成了无参无返回值的函数指针,并且还可以用转换后函数指针调用这个函数。

typedef void(*FUNC)();
int DoSomething(int i)
{cout << "DoSomething: " << i << endl;return 0;
}
int main()
{FUNC f = reinterpret_cast<FUNC>(DoSomething);f();return 0;
}

说明一下: 用转换后的函数指针调用该函数时没有传入参数,因此这里打印出参数i的值是一个随机值。

const_cast

const_cast用于删除变量的const属性,转换后就可以对const变量的值进行修改。比如:

int main()
{const int a = 2;int* p = const_cast<int*>(&a);*p = 3;cout << a << endl;  //2cout << *p << endl; //3return 0;
}

说明一下:

代码中用const_cast删除了变量a的地址的const属性,这时就可以通过这个指针来修改变量a的值。
由于编译器认为const修饰的变量是不会被修改的,因此会将const修饰的变量存放到寄存器当中,当需要读取const变量时就会直接从寄存器中进行读取,而我们修改的实际上是内存中的a的值,因此最终打印出a的值是未修改之前的值。
如果不想让编译器将const变量优化到寄存器当中,可以用volatile关键字对const变量进行修饰,这时当要读取这个const变量时编译器就会从内存中进行读取,即保持了该变量在内存中的可见性。

dynamic_cast

dynamic_cast用于将父类的指针(或引用)转换成子类的指针(或引用)。

向上转型与向下转型

向上转型: 子类的指针(或引用)→ 父类的指针(或引用)。
向下转型: 父类的指针(或引用)→ 子类的指针(或引用)。

其中,向上转型就是所说的切割/切片,是语法天然支持的,不需要进行转换,而向下转型是语法不支持的,需要进行强制类型转换。

向下转型的安全问题

向下转型分为两种情况:

如果父类的指针(或引用)指向的是一个父类对象,那么将其转换为子类的指针(或引用)是不安全的,因为转换后可能会访问到子类的资源,而这个资源是父类对象所没有的。
如果父类的指针(或引用)指向的是一个子类对象,那么将其转换为子类的指针(或引用)则是安全的。
使用C风格的强制类型转换进行向下转型是不安全的,因为此时无论父类的指针(或引用)指向的是父类对象还是子类对象都会进行转换。而使用dynamic_cast进行向下转型则是安全的,如果父类的指针(或引用)指向的是子类对象那么dynamic_cast会转换成功,但如果父类的指针(或引用)指向的是父类对象那么dynamic_cast会转换失败并返回一个空指针。比如:

class A
{
public:virtual void f(){}
};
class B : public A
{};
void func(A* pa)
{B* pb1 = (B*)pa;               //不安全B* pb2 = dynamic_cast<B*>(pa); //安全cout << "pb1: " << pb1 << endl;cout << "pb2: " << pb2 << endl;
}
int main()
{A a;B b;func(&a);func(&b);return 0;
}

上述代码中,如果传入func函数的是子类对象的地址,那么在转换后pb1和pb2都会有对应的地址,但如果传入func函数的是父类对象的地址,那么转换后pb1会有对应的地址,而pb2则是一个空指针。

说明一下: dynamic_cast只能用于含有虚函数的类,因为运行时类型检查需要运行时的类型信息,而这个信息是存储在虚函数表中的,只有定义了虚函数的类才有虚函数表。

explicit

explicit用来修饰构造函数,从而禁止单参数构造函数的隐式转换。比如:

class A
{
public:explicit A(int a){cout << "A(int a)" << endl;}A(const A& a){cout << "A(const A& a)" << endl;}
private:int _a;
};
int main()
{A a1(1);//A a2 = 1; //errorreturn 0;
}

在语法上,代码中的A a2 = 1等价于以下两句代码:

A tmp(1);  //先构造
A a2(tmp); //再拷贝构造

所以在早期的编译器中,当编译器遇到A a2 = 1这句代码时,会先构造一个临时对象,再用这个临时对象拷贝构造a2。但是现在的编译器已经做了优化,当遇到A a2 = 1这句代码时,会直接按照A a2(1)的方式进行处理,这也叫做隐式类型转换。

但对于单参数的自定义类型来说,A a2 = 1这种代码的可读性不是很好,因此可以用explicit修饰单参数的构造函数,从而禁止单参数构造函数的隐式转换。

RTTI

RTTI(Run-Time Type Identification)就是运行时类型识别。

C++通过以下几种方式来支持RTTI:

typeid:在运行时识别出一个对象的类型。
dynamic_cast:在运行时识别出一个父类的指针(或引用)指向的是父类对象还是子类对象。
decltype:在运行时推演出一个表达式或函数返回值的类型。

常见面试题

1、C++中的4种类型转换分别是:____ 、____ 、____ 、____。

分别是static_cast、reinterpret_cast、const_cast和dynamic_cast。

2、说说4种类型转换的应用场景。

static_cast用于相近类型的类型之间的转换,编译器隐式执行的任何类型转换都可用static_cast。
reinterpret_cast用于两个不相关类型之间的转换。
const_cast用于删除变量的const属性,方便赋值。
dynamic_cast用于安全的将父类的指针(或引用)转换成子类的指针(或引用)。

总结:

今天我们学习了C++中的类型转换,了解了一些有关的底层原理。接下来,我们将继续进行C++的学习。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

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

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

相关文章

微信小程序的OA会议之首页搭建

目录 一.小程序的布局 1.1. flex是什么 1.2. flex布局 1.3.总体布局 二.轮播图 2.1. 组件 2.2. 数据请求 2.3. 页面 三.首页 2.1. 视图 2.2.数据 2.3. 样式 好啦今天就到这里了&#xff0c;希望能帮到你哦&#xff01;&#xff01;&#xff01; 一.小程序的布局 …

基于 Debian 稳定分支发行版的Zephix 7 发布

导读Zephix 是一个基于 Debian 稳定版的实时 Linux 操作系统。它可以完全从可移动媒介上运行&#xff0c;而不触及用户系统磁盘上存储的任何文件。 Zephix 是一个基于 Debian 稳定版的实时 Linux 操作系统。它可以完全从可移动媒介上运行&#xff0c;而不触及用户系统磁盘上存…

PHP-FFMpeg 操作音视频

✨ 目录 &#x1f388; 安装PHP-FFMpeg&#x1f388; 视频中提取一张图片&#x1f388; 视频中提取多张图片&#x1f388; 调整视频大小&#x1f388; 视频添加水印&#x1f388; 生成音频波形&#x1f388; 音频转换&#x1f388; 给音频添加元数据&#x1f388; 拼接多个音视…

微前端四:qiankun在开发中遇到的问题

在qiankun开发中会遇到很多问题&#xff0c;上一篇微前端三&#xff1a;qiankun 协作开发和上线部署其实也是在解决一些经常遇到的问题&#xff0c;下面的两点也算是比较经典的了 1、子应用图片路径问题 2、基座是Vue2.0 element ui 配合 子应用 Vue3.0 element plus 导致的样…

Linux-git

文章目录 git简介git常用命令配置初始化仓库将文件添加到暂存区将暂存区文件加入版本库对比工作区某文件和暂存区中的区别将暂存区的文件移除但git仍管理将文件移除暂存区并且git不再管理查看版本库切换到之前的版本恢复文件持久化 云端将本地的项目推送到远程仓库将远程仓库的…

weapp-tailwindcss for uni-app 样式条件编译语法插件

weapp-tailwindcss for uni-app 样式条件编译语法插件 版本需求 2.10.0 weapp-tailwindcss for uni-app 样式条件编译语法插件 这是什么玩意?如何使用 tailwind.config.js 注册postcss 插件注册 uni-app vite vue3uni-app vue2 配置完成 配置项 这是什么玩意? 在 uni-app …

[1Panel]开源,现代化,新一代的 Linux 服务器运维管理面板

测评介绍 本期测评试用一下1Panel这款面板。1Panel是国内飞致云旗下开源产品。整个界面简洁清爽&#xff0c;后端使用GO开发&#xff0c;前端使用VUE的Element-Plus作为UI框架&#xff0c;整个面板的管理都是基于docker的&#xff0c;想法很先进。官方还提供了视频的使用教程&…

vue使用pdf-dist实现pdf预览以及水印

vue使用pdf-dist实现pdf预览以及水印 一.使用pdf-dist插件将PDF文件转换为一张张canvas图片 npm install pdf-dist二.页面引入插件 const pdfJS require("pdfjs-dist"); pdfJS.GlobalWorkerOptions.workerSrc require("pdfjs-dist/build/pdf.worker.entry&…

ubuntu18.04 LTS卸载qtcreator-10.0.2

之前通过命令&#xff0c;通过.run文件&#xff0c;安装了Qt Creator 默认安装路径是/opt/ 卸载 在安装路径下&#xff0c;可以看到QtCreatorUninstaller文件 命令行运行该执行文件&#xff0c;会弹出卸载窗口&#xff0c;记得勾选下面的“仅卸载”

el-upload实现上传文件夹

背景&#xff1a;如图一所示&#xff0c;最下面有一个黄色上传文件按钮&#xff0c;为手动上传而且上传区域有上传文件和上传文件夹的区分 所以需要在点击了上传文件夹做特殊处理使得el-upload可以上传文件夹 一、template区域 <el-uploadclass"upload-file"dra…

小程序:uniapp解决主包体积过大的问题

已经分包但还是体积过大 运行时勾选“运行时是否压缩代码”进行压缩 在manifest.json配置&#xff08;开启分包优化&#xff09; "mp-weixin" : {"optimization" : {"subPackages" : true}//.... },在app.json配置&#xff08;设置组件按需注入…

客户端post请求,服务器收到{}数据解决方法

当我们发起登录请求时&#xff0c;后台接收到的为{}数据 原因&#xff1a;传送过去的对象格式不对 解决方案&#xff1a; 引入qs npm install qs 在data中格式化数据 const res await axios({url:http://127.0.0.1:3000/post,method:post,data:Qs.stringify({username:te…

华为智选SF5,AITO问界的车怎么样

#华为智选 #赛力斯SF5 #aito问界m5 #aito问界m7 #华为汽车 华为的车&#xff0c;后杠焊两点&#xff0c;拉车的时候&#xff0c;拖车钩断了&#xff0c;后杠拉出来了&#xff0c;这质量可以吗&#xff1f;是否应该全部召回&#xff1f;M5&#xff0c;M7是不是也这样&#xff1f…

MIT6.5830 Lab0-Go tutorial实验记录(二)

MIT6.5830 Lab0-Go tutorial实验记录&#xff08;二&#xff09; – WhiteNights Site 标签&#xff1a;Golang, 数据库 在将数据库的数据转换为图表前&#xff0c;我们需要先测试是否能正常访问数据库文件。 写者注 为什么要怎么做&#xff1f;因为这块 非常容易出问题。在h…

https证书配置(nginx)

HTTPS 是什么 HTTPS 是一种应用层协议&#xff0c;是一种透过计算机网络进行安全通信的传输协议&#xff0c;HTTPS 经由 HTTP 进行通信&#xff0c;但是在 HTTP 的基础上引入了一个加密层&#xff0c;使用 SSL/TLS 来加密数据包&#xff0c;HTTPS 开发的主要目的&#xff0c;是…

作用域和作用域链

概述 本文将讲解作用域的形成和应用&#xff0c;并且在这基础上简单讲解for循环中的let创建的块级作用域原理。 一&#xff0c;作用域 1.1&#xff0c;作用域的概念 作用域是指在程序中定义变量的区域&#xff0c;该位置决定了变量的生命周期。 function testFn(){var a1 …

Zookeeper 和 Kafka 工作原理及如何搭建 Zookeeper集群 + Kafka集群

目录 1 Zookeeper 1.1 Zookeeper 定义 1.2 Zookeeper 工作机制 1.3 Zookeeper 特点 1.4 Zookeeper 数据结构 1.5 Zookeeper 应用场景 1.6 Zookeeper 选举机制 2 部署 Zookeeper 集群 2.1 安装前准备 2.2 安装 Zookeeper 3 Kafka 3.1 为什么需要消息队列&#xff08;…

SSH连接华为交换机慢

ssh连接交换机慢是因为交换计算密钥算法阶段默认使用安全性更高的秘钥&#xff0c;由于性能问题导致连接比较慢&#xff0c;如一台华为S5735S-L24T4S-QA2的交换机默认使用如下秘钥&#xff0c;安全行由高到低。 ssh server key-exchange dh_group16_sha512 dh_group15_sha512 …

Redux详解(二)

1. 认识Redux Toolkit Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法。 通过传统的redux编写逻辑方式&#xff0c;会造成文件分离过多&#xff0c;逻辑抽离过于繁琐&#xff08;具体可看上篇文章 Redux详解一&#xff09;&#xff0c;React官方为解决这一问题&#xff0c;推…

HCIP静态路由综合实验

题目&#xff1a; 步骤&#xff1a; 第一步&#xff1a;搭建上图所示拓扑; 第二步&#xff1a;为路由器接口配置IP地址&#xff1b; R1&#xff1a; [R1]display current-configuration intinterface GigabitEthernet0/0/0ip address 192.168.1.1 255.255.255.252 interfa…