理解C++强制类型转换
理解C++强制类型转换
文章目录
- 理解C++强制类型转换
- 理解C++强制转换运算符
- 1 static_cast
- 1.1. static_cast用于内置数据类型之间的转换
- 1.2 用于指针之间的转换
- 1.3 用于基类与派生类之间的转换
- 2. const_cast
- 2.1示例1
- 2.2 示例2——this指针
- 3.reinterpret_cast
- 4.dynamic_cast
- C++认为C风格的类型转换过于松散,可能会带来隐患,不够安全。
- C++推出了新的类型转换来替代C风格的类型转换,采用更严格的语法检查,降低使用风险。
- C++新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast,用于支持C++风格的类型转换。
- C++的类型转换只是语法上的解释,本质上与C风格的类型转换没什么不同,C语言做不到事情的C++也做不到。
C语言强制类型转换是有一定风险的,有的转换并不一定安全,如
- 把整型数值转换成指针;
- 把基类指针转换成派生类指针;
- 把一种函数指针转换成另一种函数指针;
- 把常量指针转换成非常量指针等。
总结:C语言强制类型转换缺点;主要是为了克服C语言强制类型转换的以下三个缺点。
- 没有从形式上体现转换功能和风险的不同。
- 将多态基类指针转换成派生类指针时不检查安全性,即无法判断转换后的指针是否确实指向一个派生类对象。
- 难以在程序中寻找到底什么地方进行了强制类型转换强制类型转换是引发程序运行时错误的一个原因,因此在程序出错时,可能就会想到是不是有哪些强制类型转换出了问题。
例如,将int 强制转换成 double是没有风险的,而将常量指针转换成非常量指针,将基类指针转换成派生类指针都是高风险的,而且后两者带来的风险不同(即可能引发不同种类的错误),C语言的强制类型转换形式对这些不同并不加以区分
举例1. 把整型数值转换成指针,编译阶段不报错,运行阶段报错
理解C++强制转换运算符
C++ 引入了四种功能不同的强制类型转换运算符以进行强制类型转换
- static cast
- const cast
- reinterpret_cast
- dynamic_cast
语法:(目标类型)表达式或目标类型(表达式);
- static_cast<目标类型>(表达式);
- const_cast<目标类型>(表达式);
- reinterpret_cast<目标类型>(表达式);
- dynamic_cast<目标类型>(表达式);
1 static_cast
1.1. static_cast用于内置数据类型之间的转换
用途:基本等价于隐式转换的一种类型转换运算符,可使用于需要明确隐式转换的地方。
可以用于低风险的转换
- 整型和浮点型
- 字符与整形
- 转换运算符
- *空指针转换为任何目标类型的指针
不可以用与风险较高的转换
- 不同类型的指针之间互相转换
- 整型和指针之间的互相转换
- 不同类型的引用之间的转换
#include <iostream>
using namespace std;
class CInt
{
public:operator int(){this->m_Int = 128;return m_Int;}
int m_Int;};
int main(int argc, char* argv[])
{int i = 3;float f = 10.0f;f = i; //可以隐式转换,会出现警告int”转换到“float”,可能丢失数据 long m = i; // 绝对安全,可以隐式转换,不会出现警告。double dd = 1.23;long m1 = dd; // 可以隐式转换,会出现可能丢失数据的警告。long m2 = (long)dd; // C风格:显式转换,不会出现警告。long m3 = static_cast<long>(dd); // C++风格:显式转换,不会出现警告。cout << "m1=" << m1 << ",m2=" << m2 << ",m3=" << m3 << endl;//低风险的转换:整型与浮点型;字符型与整型;void *指针转换为任意类型指针//字符型与整型char ch='a';int n = 5;n = static_cast<int>(ch);//void *指针转换为任意类型指针void *p = nullptr;int *p1 = static_cast<int *>(p);//转换运算符,类与其他类型CInt Obj;//int k=Obj ;//可以隐式转换int k = static_cast<int>(Obj);cout << "k=" << k << endl;}
1.2 用于指针之间的转换
C风格可以把不同类型的指针进行转换。
C++不可以,需要借助void *。
#include <iostream>
using namespace std;
class CInt
{
public:operator int(){this->m_Int = 128;return m_Int;}
int m_Int;};
int main(int argc, char* argv[])
{int i = 3;float f = 10.0f;f = i; //可以隐式转换,会出现警告int”转换到“float”,可能丢失数据 long m = i; // 绝对安全,可以隐式转换,不会出现警告。double dd = 1.23;long m1 = dd; // 可以隐式转换,会出现可能丢失数据的警告。long m2 = (long)dd; // C风格:显式转换,不会出现警告。long m3 = static_cast<long>(dd); // C++风格:显式转换,不会出现警告。cout << "m1=" << m1 << ",m2=" << m2 << ",m3=" << m3 << endl;//低风险的转换:整型与浮点型;字符型与整型;void *指针转换为任意类型指针//高风险的转换:整型与指针类型转换//字符型与整型char ch='a';int n = 5;n = static_cast<int>(ch);//void *指针转换为任意类型指针void *p = nullptr;int *p1 = static_cast<int *>(p);//转换运算符,类与其他类型CInt Obj;//int k=Obj ;//可以隐式转换int k = static_cast<int>(Obj);cout << "k=" << k << endl;//}
1.3 用于基类与派生类之间的转换
int main()
{CFather* pFather = nullptr;CSon* pSon = nullptr;//父类转子类(不安全)//pSon = pFather;pSon = static_cast<cson*>(pFather); //不安全,没有提供运行时的检测,编译会通过//子类转父类(安全)pFather = pSon;pFather = static cast<CFather*>(pSon);}
2. const_cast
- static_cast不能丢掉指针(引用)的const和volitale属性,const_cast可以。
- 仅用于进行去除
const
属性的转换,它也是四个强制类型转换运算符中唯一能够去除const
属性的运算符。 - const_cast 只针对指针,引用,this指针
2.1示例1
示例1改为
#include <iostream>
#include <string>
int main()
{const int n = 5;const std::string s = "Inception";//const_cast 只针对指针,引用,this指针int *k = const_cast<int*>(&n);//const_cast<int*>指针类型 &n取出变量地址*k = 123456;std::cout <<"改变后的值 "<< *k << std::endl;}
#include <iostream>
#include <string>
int main()
{const int n = 5;const std::string s = "Inception";//const_cast 只针对指针,引用,this指针int *k = const_cast<int*>(&n);//const_cast<int*>指针类型 &n取出变量地址int &k1 = const_cast<int&>(n);//const_cast<int&>引用类型 *k = 123456;k1 = 10000;std::cout <<"改变后的值 "<< *k << std::endl;std::cout << "改变后的值 " << k1 << std::endl;
}
2.2 示例2——this指针
常成员函数——不能修改成员变量的值,使用const_cast
让常成员函数可以修改成员变量的值,这个做法感觉有点无聊
#include <iostream>
#include <string>
class CTest
{
public:int m_test=100;void foo(int test) const{//m_test = test;//void *p = this;const_cast<CTest* const>(this)->m_test = test;//const_cast<const CTest* const>(this)->m_test = test;//报错}
};int main()
{int n = 5;int* const p=&n;//p = 0x123;CTest t;t.foo(1);std::cout << t.m_test << std::endl;//const int n = 5;//const std::string s = "Inception";const_cast 只针对指针,引用,this指针//int *k = const_cast<int*>(&n);//const_cast<int*>指针类型 &n取出变量地址//int &k1 = const_cast<int&>(n);//const_cast<int&>引用类型 //*k = 123456;//k1 = 10000;//std::cout <<"改变后的值 "<< *k << std::endl;//std::cout << "改变后的值 " << k1 << std::endl;
}
3.reinterpret_cast
static_cast不能用于转换不同类型的指针(引用)(不考虑有继承关系的情况),reinterpret_cast可以。
reinterpret_cast的意思是重新解释,能够将一种对象类型转换为另一种,不管它们是否有关系。
语法:reinterpret_cast<目标类型>(表达式);
<目标类型>和(表达式)中必须有一个是指针(引用)类型。
reinterpret_cast不能丢掉(表达式)的const或volitale属性。
应用场景:
1)reinterpret_cast的第一种用途是改变指针(引用)的类型。
2)reinterpret_cast的第二种用途是将指针(引用)转换成整型变量。整型与指针占用的字节数必须一致,否则会出现警告,转换可能损失精度。
3)reinterpret_cast的第三种用途是将一个整型变量转换成指针(引用)。
示例:
#include <iostream>
using namespace std;void func(void* ptr) { long long ii = reinterpret_cast<long long>(ptr);cout << "ii=" << ii << endl;
}int main(int argc, char* argv[])
{long long ii = 10;func(reinterpret_cast<void *>(ii));
}
4.dynamic_cast
动态转换(dynamic_cast)用于基类和派生类之间的转换,但只能在运行时确定类型信息,因此只能用于多态类型。如果转换失败,将返回一个null指针。其语法如下:
dynamic_cast<目标类型> (原始类型)
以下是几个具体例子:
1、将一个基类指针强制转换为一个派生类指针:
class Base { virtual void f(){} };
class Derived : public Base { void f(){} };
Base *b = new Derived(); // 基类指针指向派生类对象
Derived *p = dynamic_cast<Derived *>(b); // 将基类指针转换为派生类指针
2、使用 dynamic_cast 对指针进行类型判断:
class Base {};
class Derived : public Base {};Base* b1 = new Derived();
Derived* d1 = dynamic_cast<Derived*>(b1);
if (d1 != nullptr) {// b1 是 Derived 类型的。
}
需要注意的是,如果指向的基类指针并不真正指向派生类,或者目标类型与原始类型之间的类型转换无法完成,dynamic_cast会返回null指针或抛出std::bad_cast异常。因此,在使用dynamic_cast时需要非常小心,确保程序的健壮性和安全性。
相关文章:

理解C++强制类型转换
理解C强制类型转换 文章目录 理解C强制类型转换理解C强制转换运算符1 static_cast1.1. static_cast用于内置数据类型之间的转换1.2 用于指针之间的转换 1.3 用于基类与派生类之间的转换2. const_cast2.1示例12.2 示例2——this指针 3.reinterpret_cast4.dynamic_cast C认为C风格…...
《TCP/IP网络编程》代码实现
文章目录 1. 项目说明1.1 项目特点2. 文件说明2.1 脚本文件2.1.1 `TCP_IP.sln`2.1.2 `xmake.lua`2.1.2.1 编译说明2.1.2.2 运行说明2.1.3 章节说明项目代码已经开源在github上! 微信公众号文章同步发表! 1. 项目说明 根据《TCP/IP网络编程》书籍学习,对其中的代码进行整理,…...

【Python】如何使用PyInstaller打包自己写好的代码
使用PyInstaller打包自己写好的代码 零、需求 最近接到一个小单,需要批量修改文档内容,用Python做好后要打包成exe程序给客户的Win7电脑使用,此时需要用到PyInstaller打包自己的代码,想到还要有给用户试用的需求,所以…...
Java 线程的调度与时间片
🙈作者简介:练习时长两年半的Java up主 🙉个人主页:程序员老茶 🙊 ps:点赞👍是免费的,却可以让写博客的作者开兴好久好久😎 📚系列专栏:Java全栈,…...

Java项目-文件搜索工具
目录 项目背景 项目效果 SQLite的下载安装 使用JDBC操作SQLite 第三方库pinyin4j pinyin4j的具体使用 封装pinyin4j 数据库的设计 创建实体类 实现DBUtil 封装FileDao 设计scan方法 多线程扫描 周期性扫描 控制台版本的客户端 图形化界面 设计图形化界面 项目…...
记录开发中遇到关于MySQL的一些问题-MySQL版
本篇文章是记录开发中遇到关于MySQL的一些问题: 希望在这篇文章也能够找到你正在查找的问题,解决问题 Good Luck ! 关于Id 的一些问题 数据库并没有直接写SQL,是通过使用IDEA 同一个公司下的数据库软件生成的(DataGrip…...

2023-10-06 LeetCode每日一题(买卖股票的最佳时机含手续费)
2023-10-06每日一题 一、题目编号 714. 买卖股票的最佳时机含手续费二、题目链接 点击跳转到题目位置 三、题目描述 给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。 你可以无限次地完成交易&…...

openGauss学习笔记-91 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用MOT外部支持工具
文章目录 openGauss学习笔记-91 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用MOT外部支持工具91.1 gs_ctl(全量和增量)91.2 gs_basebackup91.3 gs_dump91.4 gs_restore openGauss学习笔记-91 openGauss 数据库管理-内存优化表MOT…...
PostgreSQL快速入门
PostgreSQL快速入门:轻松掌握强大的开源数据库 PostgreSQL(简称Postgres)是一款强大、可定制且免费的开源关系型数据库管理系统(RDBMS)。它以其高级功能、可扩展性和安全性而著称,被广泛用于各种规模的项目…...

MATLAB:线性系统的建模与仿真(含完整程序)
目录 前言实验内容一、先看作业题目要求二、作业正文Modeling LTI systemsEstablish model1.tf(sys2)2. tf(sys3)3.zpk(sys1)4. zpk(sys3)5. ss(sys1)6. ss(sys2)7.[num,den] tfdata(sys1)8.[num,den] tfdata(sys2)9.[num,den] tfdata(sys3)10.[num,den] tfdata(sys1,’v’…...

mycat实现mysql读写分离
架构图: 视频地址...

【C++】STL详解(十一)—— unordered_set、unordered_map的介绍及使用
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:C学习 🎯长路漫漫浩浩,万事皆有期待 上一篇博客:【C】STL…...

【C语言】动态通讯录(超详细)
通讯录是一个可以很好锻炼我们对结构体的使用,加深对结构体的理解,在为以后学习数据结构打下结实的基础 这里我们想设计一个有添加联系人,删除联系人,查找联系人,修改联系人,展示联系人,排序这几…...

Mac下docker安装MySQL8.0.34
学习并记录一下如何用docker部署MySQL 在Docker中搜索并下载MySQL8.0.x的最新版本 下载好后,在Images中就可以看到MySQL的镜像了 通过下面的命令也可以查看docker images启动镜像,使用下面的命令就可以启动镜像了docker run -itd --name mysql8.0.34 -…...

基于python编写的excel表格数据标记的exe文件
目录 一、需求: 二、思路: 三、工具 四、设计过程 (一)根据需要导入相关的图形界面库 (二)创建图形窗口 (三)标签设计 (四)方法按钮设计 ࿰…...
acwing算法基础之基础算法--高精度加法算法
目录 1 知识点2 模板 1 知识点 大整数 大整数,它们的长度都为 1 0 6 10^6 106。大整数是指长度为 1 0 6 10^6 106的整数。 大整数 - 大整数 大整数 * 小整数 大整数 / 小整数 把大整数存储到向量中,需要考虑高位在前还是低位在前,低位在前…...

openGauss学习笔记-84 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署服务器优化:x86
文章目录 openGauss学习笔记-84 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署服务器优化:x8684.1 BIOS84.2 操作系统环境设置84.3 网络 openGauss学习笔记-84 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署服务器优化:x86 …...

二分查找:34. 在排序数组中查找元素的第一个和最后一个位置
个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》《算法》 文章目录 前言一、题目解析二、解题思路1. 暴力查找2. 一次二分查找 部分遍历3. 两次二分查找分别查找左右端点1.查找区间左端点2. 查找区间右端点 三、代码实现总结 前言 本篇文…...

javaee ssm框架项目整合thymeleaf2.0 更多thymeleaf标签用法 项目结构图
创建ssmthymeleaf项目 创建ssmthymeleaf项目参考此文 thymeleaf更多常用标签 <!DOCTYPE html> <html lang"en" xmlns:th"http://www.thymeleaf.org"> <head><meta charset"UTF-8"><title>Title</title> …...

lv7 嵌入式开发-网络编程开发 11 TCP管理与UDP协议
目录 1 TCP管理 1.1 三次握手 1.2 四次挥手 1.3 保活计时器 2 wireshark安装及实验 3.1 icmp协议抓包演示 3.2 tcp协议抓包演示 3 UDP协议 3.1 UDP 的主要特点: 4 练习 1 TCP管理 1.1 三次握手 TCP 建立连接的过程叫做握手。 采用三报文握手࿱…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...