Cpp::静态 动态的类型转换全解析(36)

文章目录

  • 前言
  • 一、C语言中的类型转换
  • 二、为什么C++会有四种类型转换?
    • 内置类型 -> 自定义类型
    • 自定义类型 -> 内置类型
    • 自定义类型 -> 自定义类型
    • 隐式类型转换的坑
  • 三、C++强制类型转换
    • static_cast
    • reinterpret_cast
    • const_cast
    • dynamic_cast
  • 四、RTTI
  • 总结


前言

  Hello,学完这个,再看看 IO 流,我们的C++学习之路可能真的要结束了~


一、C语言中的类型转换

  在学习C++之前,不妨我们先看看C的类型转换的机制:

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

  C语言中总共有两种形式的类型转换:隐式类型转换(整型之间 整型浮点数之间) 和 显式类型转换(指针之间 整型指针之间)

没有关联的类型不支持转换

  1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败。
  2. 显式类型转化:需要用户自己处理。
#include<iostream>
using namespace std;int main()
{int i = 1;// 隐式类型转换double d = i;printf("%d, %.2f\n", i, d);int* p = &i;// 显示的强制类型转换int address = (int)p;printf("%p, %d\n", p, address);// “类型强制转换”: 无法从“int *”转换为“double”// double x = (double)p;// 没有关联的类型不支持转换return 0;
}

二、为什么C++会有四种类型转换?

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

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

  C++除了兼容C的转换用法之外还有三种转换方式:内置类型 -> 自定义类型 ;自定义类型 -> 内置类型 ; 自定义类型 -> 自定义类型

内置类型 -> 自定义类型

  内置类型转换为自定义类型通过 隐式类型转换 + 对应的构造函数 就能够实现

class A
{
public:A(int a1):_a1(a1){}A(int a1, int a2):_a1(a1),_a2(a2){}
private:int _a1 = 1;int _a2 = 1;
};int main()
{// 内置类型 -> 自定义类型A aa1 = 1;// 单参数隐式类型转换A aa2 = { 1,2 };// 多参数隐式类型转换,使用{}// A aa3 = { 1,2,3 };// 没有实现3个参数的构造函数或者initializer_list,就不能隐式类型转换return 0;
}

在这里插入图片描述

自定义类型 -> 内置类型

  自定义类型转化为内置类型,直接写不支持,需要写重载函数

class A
{
public:A(int a1):_a1(a1){}// 自定义类 -> 内置类型 重载函数operator int(){return _a1 + _a2;}
private:int _a1 = 1;int _a2 = 1;
};int main()
{// 内置类型 -> 自定义类型A aa1 = 1;// 自定义类型 -> 内置类型 直接写不支持,需要重载int x = aa1;cout << x << endl;return 0;
}

在这里插入图片描述

自定义类型 -> 自定义类型

  自定义类型转换为自定义类型,直接写不支持,需要加拷贝构造

class A
{
public:A(int a1):_a1(a1){}// 成员变量私有,类外不能获取,const对象需要加constint get() const{return _a1;}
private:int _a1 = 1;int _a2 = 1;
};class B
{
public:B(const A& aa):_b1(aa.get()){}
private:int _b1;
};int main()
{// 内置类型 -> 自定义类型A aa1 = 1;// 自定义类型 -> 自定义类型 直接写不支持,需要加拷贝构造B bb = aa1;return 0;
}

在这里插入图片描述

隐式类型转换的坑

// 隐式类型转换的坑
void Insert(size_t pos)
{int end = 10;while (end >= pos){cout << end << endl;--end;}
}int main()
{Insert(5);// 插入0就有坑,-1转换为无符号整数为最大值Insert(0);return 0;
}

在这里插入图片描述

三、C++强制类型转换

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

static_cast、reinterpret_cast、const_cast、dynamic_cast

static_cast

  static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast

一样的,但它不能用于两个不相关的类型进行转换

int main()
{int i = 1;// 隐式类型转换 : static_castdouble d = static_cast<double>(i);cout << d << endl;// 强制类型转换int* p = &i;//int address = static_cast<int>(p);//printf("%p %d\n", p, address);return 0;
}

在这里插入图片描述

class A
{
public:A(int a1):_a1(a1){}
private:int _a1 = 1;int _a2 = 1;
};int main()
{// 隐式类型转换,使用staticA aa1 = 1;A aa2 = static_cast<int>(1);return 0;
}

在这里插入图片描述

reinterpret_cast

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

int main()
{int i = 1;// 强制类型转换 : reinterpret_castint* p = &i;int address = reinterpret_cast<int>(p);printf("%p %d\n", p, address);return 0;
}

在这里插入图片描述

const_cast

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

int main()
{const int i = 1;// 存放到寄存器中int* ptr = (int*)&i;(*ptr)++;cout << *ptr << endl;cout << i << endl;return 0;
}

在这里插入图片描述
  我们能够看到一个很奇怪的现象,我们将 i 地址处的数据++,该地址处的值修改了,但是 i 的值却没有修改,这是为什么呢?

实际是在C++程序中,使用 const 修饰的变量是存放在寄存器中的,最终打印该值是直接打印寄存器存储的值

dynamic_cast

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

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

  1. dynamic_cast只能用于父类含有虚函数的类 。
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0。
class A
{
public:virtual void f(){}int _a1 = 1;
};class B : public A
{
public:int _b1 = 1;
};void func(A* pa)
{// 不差别转换,存在风险// 传A对象的地址,没有_b1成员,修改_b1成员则程序崩溃B* pb = (B*)pa;cout << pb << endl;pb->_b1++;
}int main()
{A a;B b;func(&a);func(&b);return 0;
}

在这里插入图片描述

class A
{
public:virtual void f(){}int _a1 = 1;
};class B : public A
{
public:int _b1 = 1;
};// 使用dynamic_cast,父类必须有虚函数
void func(A* pa)
{// pa指向a对象,转换成功// pa指向b对象,转换失败,返回nullptrB* pb = dynamic_cast<B*>(pa);if (pb){cout << pb << endl;pb->_b1++;}else{cout << "转换失败" << endl;}
}int main()
{A a;B b;func(&a);func(&b);return 0;
}

在这里插入图片描述

四、RTTI

RTTI:Run-time Type identification的简称,即:运行时类型识别

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

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


总结

  芜湖,马上就要迎来最后一节了!

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

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

相关文章

2024年终总结:技术成长与突破之路

文章目录 前言一、技术成长&#xff1a;菜鸟成长之路1. 学习与实践的结合2. 技术分享与社区交流 二、生活与事业的平衡&#xff1a;技术之外的思考1. 时间管理与效率提升2. 技术对生活的积极影响 三、突破与展望&#xff1a;未来之路1. 技术领域的突破2. 未来规划与目标 四、结…

ComfyUI实现老照片修复——AI修复老照片(ComfyUI-ReActor / ReSwapper)解决天坑问题及加速pip下载

AI修复老照片&#xff0c;试试吧&#xff0c;不一定好~~哈哈 2023年4月曾用过ComfyUI&#xff0c;当时就感慨这个工具和虚幻的蓝图很像&#xff0c;以后肯定是专业人玩的。 2024年我写代码去了&#xff0c;AI做图没太关注&#xff0c;没想到&#xff0c;现在ComfyUI真的变成了工…

思科交换机telnet配置案例

目录 1.telnet简述2.网络拓扑3.设备说明4.网络配置4.1 电脑PC ip设置4.2 网络交换机telnet配置 5.小结 1.telnet简述 Telnet是远程登录服务的一个协议&#xff0c;该协议定义了远程登录用户与服务器交互的方式。它允许用户在一台联网的计算机上登录到一个远程分时系统中&#…

WPS数据分析000006

一、排序 开始→ 排序 同文件→选项→自定义序列→输入序列 二、筛选 高级筛选 条件区域要与列表区域一样。 三、条件格式

vofa++使用方法

控件区可以添加控件用来啊多样显示 点击一个控件然后右键可以选择要添加显示的数据&#xff0c;点all表全部显示&#xff0c; 点auto可以自动布局 要用控件需要选择协议&#xff0c;不知道协议具体格式可以点击问号看看&#xff0c;并且最好用printf重定义来实现 比如我要实现F…

达梦拷贝DM_HOME的复制安装

近期一个项目需求&#xff0c;需要在没有安装包的情况下&#xff0c;将达梦数据库安装到虚机上&#xff08;生产机上安装了达梦&#xff09;&#xff0c;故采用直接打包生产机DM_HOME的方式拷贝至虚机&#xff0c;再依次执行达梦的部分指令完成安装。以下为验证的步骤&#xff…

ui文件转py程序的工具

源博客连接&#xff1a; PyCharm中利用外部工具uic转成的py文件&#xff0c;里面全是C代码&#xff0c;并非python类型的代码&#xff0c;导致大量报错。。。_pyside6-uic为什么把ui转为了c-CSDN博客 如果想把ui文件转为py文件&#xff0c;首先设置pycharm的外部工具&#xf…

hedfs和hive数据迁移后校验脚本

先谈论校验方法&#xff0c;本人腾讯云大数据工程师。 1、hdfs的校验 这个通常就是distcp校验&#xff0c;hdfs通过distcp迁移到另一个集群&#xff0c;怎么校验你的对不对。 有人会说&#xff0c;默认会有校验CRC校验。我们关闭了&#xff0c;为什么关闭&#xff1f;全量迁…

61,【1】BUUCTF WEB BUU XSS COURSE 11

进入靶场 左边是吐槽&#xff0c;右边是登录&#xff0c;先登录试试 admin 123456 admiin# 123456 admin"# 123456 不玩了&#xff0c;先去回顾下xss 回顾完就很尴尬了&#xff0c;我居然用SQL的知识去做xss的题 重来 吐槽这里有一个输入框&#xff0c;容易出现存储型…

海外问卷调查如何影响企业的经营?在品牌建设中有何指导意义?

市场调查的定义&#xff1a;通过科学的方法&#xff0c;有目的地、系统地搜集整理一些市场信息&#xff0c;其目的在于了解当下市场现状和发展前景&#xff0c;为企业生产和品牌打造提供一些科学的指导意见&#xff0c;这是任何大企业、中小企业、初创企业都必须重视的一个重要…

STM32新建不同工程的方式

新建工程的方式 1. 安装开发工具 MDK5 / keil52. CMSIS 标准3. 新建工程3.1 寄存器版工程3.2 标准库版工程3.3 HAL/LL库版工程3.4 HAL库、LL库、标准库和寄存器对比3.5 库开发和寄存器的关系 4. STM32CubeMX工具的作用 1. 安装开发工具 MDK5 / keil5 MDK5 由两个部分组成&#…

idea maven本地有jar包,但还要从远程下载

idea 中&#xff0c;java 工程执行 maven reimport&#xff0c;报jar报无法下载。 我奇了个怪&#xff0c;我明明在本地仓库有啊&#xff0c;你非得从远程下载&#xff1f; 我从供应商那里拿来的&#xff0c;远程当然没有了。 这太奇葩了吧&#xff0c;折腾好久不行。 后来…

250125-package

1. 定义 包就是文件夹&#xff0c;作用是在大型项目中&#xff0c;避免不同人的编写的java文件出现同名进而导致报错&#xff1b;想象一个场景&#xff0c;在一个根目录中&#xff0c;每一个人都有自己的一个java文件夹&#xff0c;他可以将自己编写的文件放在该文件夹里&…

系统思考—动态问题分析

“不是解决问题&#xff0c;而是根本改变它的方式&#xff0c;才能真正创造持久的成功。”——彼得德鲁克 在很多情况下&#xff0c;企业面对问题时&#xff0c;总会急于寻找解决方案&#xff0c;但这些方案往往只是暂时的“应急措施”。它们看似有效&#xff0c;却难以从根本…

系统架构设计师教材:信息系统及信息安全

信息系统 信息系统的5个基本功能&#xff1a;输入、存储、处理、输出和控制。信息系统的生命周期分为4个阶段&#xff0c;即产生阶段、开发阶段、运行阶段和消亡阶段。 信息系统建设原则 1. 高层管理人员介入原则&#xff1a;只有高层管理人员才能知道企业究竟需要什么样的信…

Golang Gin系列-5:数据模型和数据库

在这篇Gin教程的博客中&#xff0c;我们将探索如何将模型和数据库与Gin框架无缝集成&#xff0c;使你能够构建健壮且可扩展的web应用程序。通过利用流行的库并遵循最佳实践&#xff0c;你将学习如何定义模型、建立数据库连接、执行CRUD操作以及确保基于gin的项目中的数据完整性…

Moretl FileSync增量文件采集工具

永久免费: <下载> <使用说明> 我们希望Moretl FileSync是一款通用性很好的文件日志采集工具,解决工厂环境下,通过共享目录采集文件,SMB协议存在的安全性,兼容性的问题. 同时,我们发现工厂设备日志一般为增量,为方便MES,QMS等后端系统直接使用数据,我们推出了增量采…

SWPU 2022 新生赛--web题

奇妙的MD5 进入靶场 然我们输入一个特殊的字符串&#xff0c;然后我到处翻了翻&#xff0c;发现有提示 在MD5中有两个特殊的字符串 0e215962017 //MD5加密后弱比较等于自身 ffifdyop //MD5加密后变成万能密码 这里明显就是万能密码了 输入之后就来到了这个页…

PyQt6医疗多模态大语言模型(MLLM)实用系统框架构建初探(上.文章部分)

一、引言 1.1 研究背景与意义 在数字化时代,医疗行业正经历着深刻的变革,智能化技术的应用为其带来了前所未有的发展机遇。随着医疗数据的指数级增长,传统的医疗诊断和治疗方式逐渐难以满足现代医疗的需求。据统计,全球医疗数据量预计每年以 48% 的速度增长,到 2025 年将…

怎么样把pdf转成图片模式(不能复制文字)

贵但好用的wps&#xff0c; 转换——转为图片型pdf —————————————————————————————————————————— 转换前&#xff1a; 转换后&#xff1a; 肉眼可见&#xff0c;模糊了&#xff0c;且不能复制。 其他免费办法&#xff0c;参考&…