C/C++语言基础--C++四大类型转换讲解
本专栏目的
- 更新C/C++的基础语法,包括C++的一些新特性
前言
- 通过前面几节课,我们学习了抽象、封装、继承、多态、异常等概念,这一篇我们将继续学习C++的类型转换,和C语言还有很大区别的;
- 在本节课最后,也简要说了一下在计算机视角上看类型是什么样子的;
- C语言后面也会继续更新知识点,如内联汇编;
- 欢迎收藏 + 关注,本人将会持续更新。
文章目录
- 类型转换
- 问题抛出(C语言的缺陷)
- static_cast
- reinterpret_cast
- const_cast
- dynamic_cast
- 小结与类型转换本质简说
类型转换
问题抛出(C语言的缺陷)
📝 首先先回忆一下C++中的类型转换,再C语言中,类型转换很简单,只需要再需要修改类型的地方前添加(datatype)
,datatype为要转换的类型 ,但是这样其实是很不严谨的,我们来看一下这样一个案例==(C语言中)==:
#include <stdio.h>int main()
{const int a = 10;const int* p = &a;int* pp = (int*)p;*pp = 20;printf("%d %d %d\n", a, *p, *pp);
}
📤 输出:
20 20 20
这个时候我们来分析一下,变量a
是一个const修饰
的变量,我们也声明了一个指针常量p
,指向变量a的地址,这个时候我们通过强制转换,强制转换成==int*==类型,将指针p
转换成普通指针pp
,这个时候通过指针pp
修改变量a的值,然后输出,通过输出发现,将常量a修改成功了,这显然不符合常理,💁♂💁♂💁♂,注意:这个时候如果用CPP
文件去运训,会得到以下结果:
10 20 20
这是因为C++他做了优化,会将a变量再只读区域储存一份,这个可以参考之前的博客: C/C++的不同
所以,C++为了规范C中的类型转换,加强类型转换的可视性,引入了四种强制类型转换操作符:
- static_cast:
- reinterpret_cast:
- const_cast:
- dynamic_cast:
下面我们分别来学习这几个类型转换。
static_cast
static_cast(expression),该运算符把expression转换为type-id类型
static_cast
关键字是再编译阶段完成的,不提供动态类型检查,所以再我们写的时候就需要经量保证这个类型之间是可以转换的,防止出现上行转换这样的,当然现在很多编译器都有自己的检查机制,会自动帮我们检查,如vs,但是linux上编程是不会的。
🌾 应用:编译器隐式执行任何类型转换都可由static_cast显示完成,编译器隐式:编译器再编译的时候自动帮我们操作,所以我们需要保证再写的时候需要保证可以转换,这个就得看经验积累了,常用如下:
-
⚾️ 基本类型转换
double score = 59.5; int nScore = static_cast<int>(score);
-
⚡️ void指针和其他类型指针之间的转换
void* p = new int(20); int* pi = static_cast<int*>(p); void* pc = static_cast<void*>(pi); //这里可以隐式转换,可以省略static_cast delete p;
-
🅿️ 用于基类派生类之间指针、引用的转换
class Base { public:virtual void show(){std::cout << "Base " << std::endl;} };class Derive :public Base {char* name = nullptr; public:Derive(){name = new char[5]{ "玩蛇" };}~Derive(){delete name;}void print(){std::cout << "Derive " << name << std::endl;} };
- 🆙 **上行转换:**把派生类指针、引用转为基类的指针、引用(可以自动隐式转换)
//指针 Derive* derive = new Derive; Base* base = static_cast<Derive*>(derive); // 转换成基类 //引用 Derive& refDerive = *derive; Base& refBase = static_cast<Base&>(refDerive); // 转换成基类delete derive;
- ⏬ **下行转换:**把基类指针、引用转为派生类的指针、引用(必须强制静态转换)
Base* base = new Base; Derive* derive = static_cast<Derive*>(base); derive->print();delete base;
⚠️ **注意:**下行转换使用
static_cast
不安全,请使用dynamic_cast
(不安全:因为不知道基类的指针,到底是不是指向的要转换的派生类对象,如果不是,访问数据成员会有错误)
reinterpret_cast
这个可以用于:任意指针之间的转换,不安全,不推荐使用,了解即可。
主要用于以下六种情况:
-
任意类型指针之间的转换
int* p = nullptr; char* pc = reinterpret_cast<char*>(p);
-
指针转整型,整型转指针
int* p = nullptr; uint64_t a = reinterpret_cast<uint64_t>(p); //x64 指针是8个字节,所以要用uint64_t保存,否则可能会丢失数据 double* pd = reinterpret_cast<double*>(a);
-
函数指针也可以转换
uint64_t funMax = reinterpret_cast<uint64_t>(_max); cout<<reinterpret_cast<int(*)(int, int)>(funMax)(2, 3);int _max(int a, int b) {return a > b ? a : b; }
-
一个官方案例
int arr[10]; for (int i = 0; i < 10; i++) {cout << arr+i <<" " <<hex<< ::hash(arr+i) << endl;; }uint32_t _hash(void* p) {uint64_t val = reinterpret_cast<uint64_t>(p);return val ^ (val >> 32); }
const_cast
const_cast用来移除类型的const属性,所以,const_cast 中的类型必须是指针、引用或指向对象类型成员的指针(引用的本质也是常量指针).
-
const指针、引用不能直接赋值给非const的对象,需要去掉const之后再赋值
const char* name = "hello"; char* pname = const_cast<char*>(name); // 转化成非const类型const int& refA = 8; int& refB = const_cast<int&>(refA);
-
可以在类的const函数里面修改成员变量
class Integer { private:int number; public:Integer(int number = 0):number(number){}operator int()const // const:说明里面的不允许有变量发送改变{const_cast<int&>(number)++; //必须去掉const才能修改const_cast<Integer*>(this)->number++;return number;} };Integer num = 10; int n = num; //11
dynamic_cast
dynamic_cast用于有继承关系的多态类(基类必须有虚函数)的指针或引用之间的转换,即,父子类之间的转换,且安全。
- 通过dynamic_cast,将派生类指针转换为基类指针(上行转换),这个操作与static_cast的效果是一样的。
- 通过dynamic_cast,将基类指针转换为派生类指针(下行转换),dynamic_cast具有类型检查的功能,比static_cast更安全(如果转换的是指针,失败时会返回空指针;如果转换的是引用,会抛出std::bad_cast异常)
🙈 使用场景:
-
指针转换,转换失败返回nullptr,更安全
Animal* dog = new Dog; dog->cry(); //转成实际的类型 Dog* d = dynamic_cast<Dog*>(dog); if (!d)std::cout << "dog is not Dog" << std::endl; d->cry(); //尝试转成其他子类,失败返回nullptr Cat* cat = dynamic_cast<Cat*>(dog); // 子转化成父 if (!cat)std::cout << "dog is not Cat"; elsecat->cry();
-
转换引用,转换失败抛异常std::bad_cast,更安全
Animal& refA = *dog; //转成实际的类型 Dog& refD = dynamic_cast<Dog&>(refA); // 父转化成子 refD.cry(); //尝试转成其他子类,失败抛异常 Cat& refC = dynamic_cast<Cat&>(refA); refC.cry();
小结与类型转换本质简说
- static_cast:最常用,用于普通类型转换
- reinterpret_cast:任意指针之间转换,不推荐使用
- const_cast:用去去掉const属性
- dynamic_cast:主要用于基类与派生类之间的转换
👀👀👀 其实再计算机内部,他是没有类型这一概念的,汇编也没有类型这一概念,类型是高级语言自己抽象出来的,类型转换就是告诉编译器这个变量属于什么类型,这样再转化成汇编的时候就可以调用不同类型的汇编指令了,当然还有很多要注意的,比如说:无符号与有符号之间的转换,-1类型转换如果从位的角度来看,转化成1,就不单单只是加个负号这么简单了,这个本人会更新后面会更新《深入理解计算机系统》这本书学习笔记,到时候会有详细的讲解🔈。
相关文章:
C/C++语言基础--C++四大类型转换讲解
本专栏目的 更新C/C的基础语法,包括C的一些新特性 前言 通过前面几节课,我们学习了抽象、封装、继承、多态、异常等概念,这一篇我们将继续学习C的类型转换,和C语言还有很大区别的;在本节课最后,也简要说…...

KafKa 集群【docker compose】
文章目录 主机准备部署编辑 docker-compose.ymlcontrollerbroker生成cluster_id 一篇完整的 docker-compose.yml 文件查看集群状态使用 kafka-ui 查看拉取 kafka-ui添加集群查看集群状态 使用命令行查看 配置讲解controllerbroker 主机准备 IPcontroller idbroker id192.168.1…...

【工具篇】MLU运行XInference部署手册
文章目录 前言一、平台环境准备二、代码下载三、安装部署1.正常pip 安装 四、运行结果展示1.如果界面404或没有东西请这样做2.运行效果 前言 Xorbits Inference(Xinference)是一个功能强大、用途广泛的库,旨在为语言、语音识别和多模态模型提…...

计算机网络:数据链路层 —— 扩展共享式以太网
文章目录 共享式以太网共享式以太网存在的问题在物理层扩展以太网扩展站点与集线器之间的距离扩展共享式以太网的覆盖范围和站点数量 在链路层扩展以太网网桥的主要结构网桥的基本工作原理透明网桥自学习和转发帧生成树协议STP 共享式以太网 共享式以太网是当今局域网中广泛采…...
平安养老险深圳分公司:创新养老服务,深入践行金融为民
党的二十届三中全会《决定》提出:“积极发展科技金融、绿色金融、普惠金融、养老金融、数字金融,加强对重大战略、重点领域、薄弱环节的优质金融服务。” 为经济社会发展提供高质量服务,更好满足人民日益增长的美好生活需要,金融…...

静态站点生成器哪家强?
有一种方法,让你写好文档后,快速地让同事、用户和合作伙伴看到,这就是静态站点生成器。 静态站点生成器是一种软件,用于创建不需要服务器端脚本的网站。这些网站由纯HTML文件组成,可能还包括CSS和JavaScript来增强功…...

从0开始部署优化虚拟机
一,vm workstation 安装 CentOS-7 忽略 二、查看虚拟机IP ip address 得到 192.168.196.128/24 宿主机进行Ping测试 C:\Users\Administrator>ping 192.168.196.128正在 Ping 192.168.196.128 具有 32 字节的数据: 来自 192.168.196.128 的回复: 字节32 时间…...

录屏有道, 四款必备录屏工具推荐!
制作教程视频、游戏直播或是远程会议记录等都需要录屏,那么到底应该怎么录屏呢?接下来就给大家介绍几个好用的录屏工具 Foxit REC 直达链接:www.foxitsoftware.cn/REC/ 操作教程:立即获取 Foxit REC以其强大的功能、简洁的界面…...

5G NR:UE初始接入信令流程浅介
UE初始接入信令流程 流程说明 用户设备(UE)向gNB-DU发送RRCSetupRequest消息。gNB-DU 包含 RRC 消息,如果 UE 被接纳,则在 INITIAL UL RRC MESSAGE TRANSFER 消息中包括为 UE 分配的低层配置,并将其传输到 gNB-CU。IN…...
探索 Spring AI:Java 开发者的 AI 应用开发新利器
在当今这个由人工智能驱动的时代,AI 技术正在以前所未有的速度改变着我们的工作和生活方式。对于 Java 开发者来说,将 AI 能力集成到他们的应用程序中,已经成为了一个迫切的需求。阿里云开源的 Spring AI Alibaba 框架,正是为了满…...

Linux历史
Linux 于 1991 年由芬兰学生 Linus Torvalds 作为个人项目开始,旨在创建一个新的免费操作系统内核。在其历史发展中,Linux 内核经历了持续的增长。自 1991 年首次发布源代码以来,Linux 内核从少量的 C 语言文件,且受限于禁止商业发…...
C++ 方法积累
std::numeric_limits<UInt32>::max()placement new 用于控制分配空间 PostingListInMemory * posting_list arena.alloc<PostingListInMemory>();new (posting_list) PostingListInMemory();/// placement new;PostingListInMemory & operator(const Posting…...

区块链-智能合约Solidity编程
文章目录 一、ubuntu安装二、FISCO BCOS安装五、 WeBASE安装5.1 WeBASE简介5.2 节点前置服务搭建5.3 调用HelloWorld合约 七、Solidity极简入门7.1. 值类型7.2. 变量数据存储和作用域7.3. 函数7.4 控制流7.5 数组&映射7.6 结构体7.7 修饰符7.8 事件7.9 面向对象7.10 抽象合…...

VS Code创建VUE项目(一)工具安装与项目创建
一.安装与配置npm 1.下载安装Node.js 安装Node.js 下载地址: Node.js — 在任何地方运行 JavaScript (nodejs.org)或下载 | Node.js 中文网 下载后一步步安装就好(安装过程基本一路直接“NEXT”就可以了,直到Finished)&#x…...

cudnn8编译caffe过程(保姆级图文全过程,涵盖各种报错及解决办法)
众所周知,caffe是个较老的框架,而且只支持到cudnn7,但是笔者在复现ds-slam过程中又必须编译caffe,我的cuda版本是11.4,最低只支持到8.2.4,故没办法,只能编译了 在此记录过程、报错及解决办法如下; 首先安装依赖: sudo apt-get install git sudo apt-get install lib…...

Docker安装Nginx
前提:Docker已安装好,本人使用的为自带docker的云服务器,docker常用命令已掌握,yjj为在根目录创建的一个文件夹,可自行修改对应的目录。 1、安装镜像,可去dockerhub上面找,一般都是组件名称。do…...
大数据治理:构建新时代数据生态的关键
摘要 随着信息技术的飞速发展和数字化浪潮的席卷,大数据已成为当今社会的核心资源。如何有效治理大数据,不仅关系到数据资源的利用效率,还对隐私保护、网络安全和社会秩序产生深远影响。本文深入探讨了大数据治理的概念、面临的挑战以及治理框架的构建,从技术、法律和伦理等…...
Leetcode 1223 LCA of Deepest TreeNode
题意,找到所有最深的叶子节点的LCA https://leetcode.com/problems/lowest-common-ancestor-of-deepest-leaves/description/ 第一个想法是模块的想法, LCA 找到所有最深的叶子节点两两组合 可行,但是算法复杂度很高而且你先要从顶到下,再从…...

C++从入门到起飞之——红黑树 全方位剖析!
🌈个人主页:秋风起,再归来~🔥系列专栏:C从入门到起飞 🔖克心守己,律己则安 目录 1. 红⿊树的概念 2. 红⿊树的实现 2.1 构建整体框架 2.2 红黑树的插入 2.3 红黑树的验证 2.4 红黑树…...

Java基于SSM微信小程序物流仓库管理系统设计与实现(lw+数据库+讲解等)
选题背景 随着社会的发展,社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景,运用软件工程原理和开发方法,它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...