【C++】告别“类型转换”踩坑,从基础到四种核心强制转换方式

【C++】告别“类型转换”踩坑,从基础到四种核心强制转换方式

各位大佬好,我是落羽!一个坚持不断学习进步的学生。
如果您觉得我的文章还不错,欢迎多多互三分享交流,一起学习进步!
也欢迎关注我的blog主页:
落羽的落羽

文章目录

一、回顾C语言的类型转换

C语言的类型转换主要是隐式类型转换和强制类型转换:

  • 隐式类型转换,是编译器在特定情况下自动进行的类型转换,通常发生在不同类型的表达式运算中。主要是整型之间、整型与浮点型之间、浮点型之间的转换。
int a =1;double b =2.234; a = b;
  • 强制类型转换:是我们通过显式语法手动指定的类型转换,主要是整型和指针、指针和指针之间的转换。
int a =1;char* p =(char*)a;int* p1 =(int*)malloc(sizeof(int));

但是,并非所有类型直接都能转换。例如double就无法转为指针类型。

在这里插入图片描述

二、C++中的类型转换

1. 内置类型转为自定义类型

随着自定义类型的广泛使用,C++也支持了内置类型和自定义类型之间的相互转换:

  • 内置类型转换为自定义类型,需要自定义类型的相关构造函数支持。非常好理解,用内置类型转换为自定义对象,就相当于构造一个自定义对象。
classA{public:A(int a):a1(a),a2(a){}private:int a1;int a2;};
在这里插入图片描述

而当构造函数前加上关键字explicit,可以使这个构造函数不支持隐式类型转换。这就是之前我们学习智能指针时构造函数加了它的原因,我们不希望一个普通指针悄悄转换为智能指针。不过,还是支持强制类型转换的

在这里插入图片描述

2. 自定义类型转为内置类型

一个自定义类型对象想要转换为内置类型,需要内部重载operator()。这里不是常规的运算符重载,和仿函数中重载operator()的写法也不一样。它的用法是operator 类型(){...}(也可以加explicit修饰),转换的方式是函数体内自定义的,举个例子:

classA{public:A(int a):a1(a),a2(a){}operatorint(){return a1 + a2;}private:int a1;int a2;};
在这里插入图片描述

智能指针中,关于向bool类型的转换,就是这样写的:

在这里插入图片描述

3. 自定义类型之间的转换

自定义类型之间的转换,也是需要有相关的构造函数,很好理解,不再赘述。

4. 类型安全与C++的四种强制类型转换方式

4.1 什么是类型安全?

类型安全是指,编程语言在编译和运行时提供保护机制,避免非法的类型转换和操作,导致出现内存访问错误等,从而减少程序运行时的错误。

C语言不是类型安全的语言, 因为C语言允许隐式类型转换,一些特殊情况下就会导致越界访问的内存错误。不合理的使用强制类型转换也会导致问题,比如一个int*的指针强转成 double*的话,访问就会出现越界。
C++兼容C语言,也支持隐式类型转换和强制类型转换,它也不是类型安全的语言。因此,C++提出了四个显示强制类型转换 操作符static_cast / reinterpret_cast / const_cast / dynamic_cast,就是为了让类型转换相对而言更安全。

4.2 static_cast

static_cast用于两个意义相近的类型之间的转换,比如整型之间、整型和浮点型之间、普通类型和其引用类型之间等。

double a =1.234;int b =static_cast<int>(a);float c =static_cast<float>(b);int&& d =static_cast<int&&>(b);

4.3 reinterpret_cast

reinterpret_cast用于底层的类型转换,比如将一种类型的指针/引用直接转换为另一种类型。这种类型的转换后,对于内存的访问方式就会改变了,因此使用时需要很谨慎,自己要清楚明白使用后是否会出现问题。

int a =1;int* p1 =&a;char* p2 =reinterpret_cast<char*>(p1);

4.4 const_cast

const_cast用于const对象向非const对象的转换,会去掉const属性,使用时同样需要谨慎。

在这里插入图片描述

4.5 dynamic_cast

dynamic_cast主要用于多态类型之间的转换,尤其是用于基类指针/引用向派生类指针/引用的转换,因为派生类的指针/引用向基类指针/引用的转换是天然支持的(也就是切片)。
但是,它不是简单基类转换为派生类。一个基类的指针/引用,它可能指向的是一个基类的对象,也可能指向的是一个派生类对象的切片。dynamic_cast只能作用在后者,只有这个基类指针/引用指向的是派生类对象的切片,才能完成转换。对于前者情况,就不能转换,如果是基类指针指向基类,转换失败返回nullptr,如果是基类引用指向基类,转换失败抛出bad_cast异常

dynamic_cast还要求基类必须是多态类型,也就是必须有虚函数,因为它的运行时通过虚表中存储的type_info来判断一个基类指针/引用指向的是基类对象还是派生类对象。

classA{public:virtualvoidfunc(){}};classB:publicA{};
在这里插入图片描述

本篇完,感谢阅读

Read more

初学二叉搜索树踩坑多?C++ 从原理到代码,搞定增删查全流程

初学二叉搜索树踩坑多?C++ 从原理到代码,搞定增删查全流程

🎬 个人主页:Vect个人主页 🎬 GitHub:Vect的代码仓库 🔥 个人专栏: 《数据结构与算法》《C++学习之旅》《计算机基础》 ⛺️Per aspera ad astra. 文章目录 * 1. 二叉搜索树相关概念 * 2. 二叉搜索树的操作 * 2.1. 查找节点 * 2.2. 插入节点 * 2.3. 删除节点 * 3. 二叉搜索树的实现 * 4. 二叉搜索树的应用 * 4.1. K模型 * 4.2. KV模型 1. 二叉搜索树相关概念 如下图所示,二叉搜索树(binary search tree)满足下列条件: 1. 对于根节点,左子树中所有节点的值<根节点的值&

By Ne0inhk
《C++:从代码到机器》:vector 的坑只有 C++ 党懂?介绍使用 + 深度剖析 + 模拟实现,帮你全避开

《C++:从代码到机器》:vector 的坑只有 C++ 党懂?介绍使用 + 深度剖析 + 模拟实现,帮你全避开

✨ 孤廖:个人主页 🎯 个人专栏:《C++:从代码到机器》 🎯 个人专栏:《Linux系统探幽:从入门到内核》 🎯 个人专栏:《算法磨剑:用C++思考的艺术》 折而不挠,中不为下 文章目录 * 正文 * 1.vector的介绍及使用 * 1.1 vector的介绍 * 1.2 vector的使用 * 1.2.1 vector的定义 * 1.2.2 vector iterator 的使用 * 1.2.3 vector 空间增长问题 * 1.2.4 vector 增删查改 * 1.2.5 vector 迭代器失效问题。(重点)

By Ne0inhk
【Linux】别再用printf了!自己造个C++日志库

【Linux】别再用printf了!自己造个C++日志库

文章目录 * 什么是日志(Log)? * 1. 日志的定义 * 2. 常见的日志级别 * 实现日志类 * 思路 * 输出方式的实现 * 日志类 * 运行结果 * 总结 什么是日志(Log)? 1. 日志的定义 日志(Log)是程序运行时记录的重要信息,通常用于调试、监控和故障排查。它可以帮助开发者了解程序的运行状态,分析错误,甚至用于安全审计。 2. 常见的日志级别 级别描述DEBUG详细信息,仅在调试时使用INFO关键信息,如程序启动、结束等WARNING警告信息,不影响运行,但需要注意ERROR发生错误,可能影响功能FATAL严重错误,程序可能崩溃 实现日志类 思路 [2024-08-0412:27:03][DEBUG][202938][main.cc][16]- hello world 我们想实现一个日志类,是这样的,

By Ne0inhk
【第53节】Windows编程必学之使用C++写exe压缩加密壳

【第53节】Windows编程必学之使用C++写exe压缩加密壳

目录 一、实现背景 1.1 前言 1.2 前置知识 1.3 达到目标 二、壳的实现要点 2.1 写壳怎么做 2.2 写壳的困难点 2.3 如何写壳代码 2.4 API函数的调用问题 2.5 重定位问题 2.6 信息交互问题 2.7 调试问题 2.8 关于目标程序的随机基址 2.9 关于目标程序的导入表 2.10 关于动态加解密 2.11 关于TLS的处理 三、实现一个壳的步骤 四、

By Ne0inhk