理解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 建立连接的过程叫做握手。 采用三报文握手࿱…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...

GraphQL 实战篇:Apollo Client 配置与缓存
GraphQL 实战篇:Apollo Client 配置与缓存 上一篇:GraphQL 入门篇:基础查询语法 依旧和上一篇的笔记一样,主实操,没啥过多的细节讲解,代码具体在: https://github.com/GoldenaArcher/graphql…...
Pydantic + Function Calling的结合
1、Pydantic Pydantic 是一个 Python 库,用于数据验证和设置管理,通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发(如 FastAPI)、配置管理和数据解析,核心功能包括: 数据验证:通过…...

EasyRTC音视频实时通话功能在WebRTC与智能硬件整合中的应用与优势
一、WebRTC与智能硬件整合趋势 随着物联网和实时通信需求的爆发式增长,WebRTC作为开源实时通信技术,为浏览器与移动应用提供免插件的音视频通信能力,在智能硬件领域的融合应用已成必然趋势。智能硬件不再局限于单一功能,对实时…...
FTXUI::Dom 模块
DOM 模块定义了分层的 FTXUI::Element 树,可用于构建复杂的终端界面,支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...

【笔记】AI Agent 项目 SUNA 部署 之 Docker 构建记录
#工作记录 构建过程记录 Microsoft Windows [Version 10.0.27871.1000] (c) Microsoft Corporation. All rights reserved.(suna-py3.12) F:\PythonProjects\suna>python setup.py --admin███████╗██╗ ██╗███╗ ██╗ █████╗ ██╔════╝…...