【C++】听说了吗,C++引入了四种强制类型转换

【C++】听说了吗,C++引入了四种强制类型转换
头像

⭐️个人主页:@小羊⭐️所属专栏:C++11新特性很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~

动图描述

目录


一、类型转换

1、C语言中的类型转换

如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与
接收返回值类型不一致时,就需要发生类型转化,转换的前提是类型之间有一定的关联。

  • 隐式类型转换:编译器自动进行,比如整形家族(int、char、unsigned int)/ 整型和浮点数
  • 强制类型转换:我们自己处理,比如整形和指针、指针之间
intmain(){int i =1;// 隐式类型转换double d = i;int* p =&i;// 显示的强制类型转换int address =(int)p;return0;}

2、C++中的类型转换

上面举的例子都是内置类型之间,而内置类型和自定义类型之间自定义类型和自定义类型之间都是可以通过一定的方式互相转换的。

| 内置类型和自定义类型之间:

在前面的学习中我们经常说:单参数构造函数支持隐式类型转换,多参数也可以通过加{}进行隐式类型转换。

classA{public:A(int a):_a1(a),_a2(a){}A(int a1,int a2):_a1(a1),_a2(a2){}private:int _a1;int _a2;};intmain(){ string s("Are you ok?");//隐式类型转换 A a1(1);//借助构造函数完成类型转换 A a2({1,2});return0;}
  • C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数
  • 构造函数前加explicit就不再支持隐式类型转换(但是还可以强转)

而自定义类型转换为内置类型需要通过下面这个函数:

operatorint(){//...}
  • 这个函数没有返回类型,但是有返回值
  • 函数前加explicit就不再支持隐式类型转换(但是还可以强转)
classA{public:A(int a):_a1(a),_a2(a){}A(int a1,int a2):_a1(a1),_a2(a2){}operatorint(){return _a1 + _a2;}private:int _a1;int _a2;};intmain(){ string s("Are you ok?");//隐式类型转换 A a1(1);//借助构造函数完成类型转换 A a2({1,2});int x = a1;int y = a2; cout << x << endl; cout << y << endl;return0;}

| 自定义类型和自定义类型之间:

自定义类型之间也可以借助构造函数来完成相互转换。

classA{public:A(int a):_a1(a),_a2(a){}A(int a1,int a2):_a1(a1),_a2(a2){}operatorint(){return _a1 + _a2;}intget()const{return _a1 + _a2;}private:int _a1;int _a2;};classB{public:B(int b):_b(b){}B(const A& aa):_b(aa.get()){}private:int _b;};intmain(){ A aa(1); B bb(2); bb = aa;//这里走了B的拷贝构造return0;}

例如:我们之前实现的list的迭代器有普通迭代器和const迭代器两种,普通迭代器用普通迭代器接收,const迭代器用const迭代器接收,而库中的list是支持普通迭代器用const迭代器接收的,那我们也可以给自己的list加上这个功能。

在这里插入图片描述

增加一个用于类型转换的构造函数:

//...ListIterator(const ListIterator<T, T&, T*>& it):_node(it._node){}//...
注意:这里的参数一定是写死的,不能是const ListIterator<T, Ref, Ptr>& it

3、C语言类型转换的缺陷

  1. 转换的可视性差,所有的转换形式都是以一种相同的形式书写,难以跟踪错误的转换
  2. 隐式类型转换有些情况下可能会出现问题,比如数据精度丢失
  3. 显示类型转换将所有情况混在一起,代码不够清晰

4、C++中的四种强制类型转换

标准C++为了加强类型转换的可视性,引入了下面四种命名的强制类型转换操作符。主要是为了让类型转换有统一的规范,更加严谨。

4.1 static_cast

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

intmain(){double d =3.14;int a =static_cast<int>(d); cout << a << endl;return0;}

4.2 reinterpret_cast

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

intmain(){double d =3.14;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); cout << p << endl;return0;}

4.3 const_cast

const_cast最常用的用途就是删除变量的const属性对应强制类型转换中有风险的去掉const属性),方便赋值。

intmain(){constint a =2;int* p =const_cast<int*>(&a);*p =3; cout << a << endl;}
在这里插入图片描述

使用volatile可以确保编译器不会对这些变量的访问进行优化,从而确保每次访问都能读取到最新的值。

在这里插入图片描述

4.4 dynamic_cast

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

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

注意:

  1. dynamic_cast只能用于父类含有虚函数的类
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回nullptr
classA{public:virtualvoidf(){}};classB:publicA{};voidfun(A* pa){// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回 B* pb1 =static_cast<B*>(pa); B* pb2 =dynamic_cast<B*>(pa); cout <<"pb1:"<< pb1 << endl; cout <<"pb2:"<< pb2 << endl;}intmain(){ A a; B b;fun(&a);fun(&b);return0;}
在这里插入图片描述

dynamic_cast 作用于普通指针或引用,用于将基类指针(或引用)转换为派生类指针(或引用) 。

另外还有 dynamic_pointer_cast,专门用于智能指针的类型转换 ,将一个基类智能指针转换为派生类智能指针 。

二者都在运行时进行类型检查以确保转换安全性。


本篇文章的分享就到这里了,如果您觉得在本文有所收获,还请留下您的三连支持哦~

头像

Read more

亮数据与AI深度融合,开发者高效采集数据的最优解

亮数据与AI深度融合,开发者高效采集数据的最优解

亮数据与AI深度融合,开发者高效采集数据的最优解 前言 AI时代优质大规模的数据对于训练精准、强大的 AI 模型至关重要,开发者在数据采集过程中面临许多难题:数据来源分散、采集效率低下、反爬虫机制阻碍等。亮数据与 AI 实现深度融合,可以解决像网页抓取 API、网页解锁器 API、抓取浏览器、抓取函数、搜索引擎爬虫等,满足开发者从常规网页数据提取到攻克复杂反爬虫网站等多样化需求,更有数据集市场与自定义数据集服务提供现成或定制化数据资源,技术上亮数据运用先进反封锁与验证码处理技术突破障碍,严格保障数据质量,提高开发者工作效率。 亮数据采集亚马逊电商数据 1、打开亮数据用户控制台代理与抓取,点击抓取浏览器(使用内置解锁和代理基础设施的全功能浏览器扩展动态抓取) 2、抓取器类型选择(根据自己的需求选择合适的抓取器)抓取浏览器:新的数据收集器与 Puppeteer、Playwright 和 Selenium 等常用自动化工具兼容,提供多步骤抓取解决方案。利用动态住宅 IP 网络,能有效处理 CAPTCHA(验证码),还集成亮数据所有解锁工具。适用于需进行复杂网页交互、

By Ne0inhk
【JAVA 进阶】Spring Boot自动配置详解

【JAVA 进阶】Spring Boot自动配置详解

文章目录 * 一、Spring Boot 与自动配置初相识 * 1.1 Spring Boot 简介 * 1.2 自动配置的概念 * 1.3 自动配置的重要性 * 二、Spring Boot 自动配置核心原理 * 2.1 核心注解 @EnableAutoConfiguration * 2.2 AutoConfigurationImportSelector * 2.3 Spring Factories 机制 * 三、自动配置实战演练 * 3.1 创建 Spring Boot 项目 * 3.2 配置文件详解 * 3.3 自定义自动配置 * 四、自动配置高级应用与问题解决 * 4.1

By Ne0inhk
Java各大厂实习面试题面经新鲜出炉!---壹

Java各大厂实习面试题面经新鲜出炉!---壹

🌟 Hello,我是Java学习通! 🌈 在彩虹般绚烂的技术栈中,我是那个永不停歇的色彩收集者。 🦋 每一个优化都是我培育的花朵,每一个特性都是我放飞的蝴蝶。 🔬 每一次代码审查都是我的显微镜观察,每一次重构都是我的化学实验。 🎵 在编程的交响乐中,我既是指挥家也是演奏者。让我们一起,在技术的音乐厅里,奏响属于程序员的华美乐章。 目录 1.MySQL事务机制(阿里巴巴) 2.有做过SQL优化的实现么(阿里巴巴) 3.Nacos底层是如何实现注册中心功能的:(阿里巴巴) 4.RocketMQ如何持久化(阿里巴巴) 5.介绍一下websocket(阿里巴巴) 6.如何判断是http是长连接还是短连接,怎么设置长连接(阿里巴巴) 7.HashMap的实现原理(快手) 8.HashMap承载的元素越来越少,什么时候会退化成链表,为什么两者设置的这个值不对称(快手) 9.mysql和redis的一致性怎么保证的(快手) 10.数据库有哪些隔离级别 默认的隔离级别是什么(快手) 11.缓存击穿

By Ne0inhk
【Java 开发日记】我们来说一下 Mybatis 的缓存机制

【Java 开发日记】我们来说一下 Mybatis 的缓存机制

目录 核心概览 一级缓存 1. 作用域 2. 工作机制 3. 示例说明 4. 注意事项 二级缓存 1. 作用域 2. 开启与配置 3. 工作机制 4. 示例说明 5. 注意事项 缓存顺序与总结 使用建议 核心概览 * 一级缓存:默认开启,作用范围在 同一个 SqlSession 内。 * 二级缓存:需要手动配置开启,作用范围在 同一个 Mapper 命名空间(即同一个 Mapper 接口)内,可以被多个 SqlSession 共享。 一级缓存 1. 作用域 * SqlSession 级别:当同一个

By Ne0inhk