【c++】c++的四种类型转换(static_cast,reinterpret_cast,const_cast,dynamic_cast)

【c++】c++的四种类型转换(static_cast,reinterpret_cast,const_cast,dynamic_cast)
小编个人主页详情<—请点击
小编个人gitee代码仓库<—请点击
c++系列专栏<—请点击
倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己!

目录


前言

【c++】特殊类的设计(不能拷贝的类,只能在堆/栈上创建对象的类,不能被继承的类,单例模式——饿汉模式、懒汉模式)——书接上文 详情请点击<——
本文由小编为大家介绍——【c++】c++的四种类型转换(static_cast,reinterpret_cast,const_cast,dynamic_cast)

一、c语言中的类型转换

在c语言中,如果赋值运算符左右两侧类型不匹配,形参和实参的类型不匹配,返回值类型和接收返回值的类型不匹配就会发生类型转换
c语言中共有两种类型转换:隐式类型转换和显示的强制类型转换

隐式类型转换

  1. 隐式类型转换:隐式类型转换会产生临时变量,编译器在编译阶段进行,如果转换失败,则编译失败,可以隐式转换极为相近的类型,比如浮点数和整形进行转换,对于单参数的构造函数也支持隐式类型转换,c++11中也支持了多参数的隐式类型转换
#include<iostream>usingnamespace std;classA{public:A(int a):_a(a){}private:int _a;};classB{public:B(int b,int c):_b(b),_c(c){}private:int _b;int _c;};intmain(){//隐式类型转换int a =0;double b = a;//单参数的构造函数可以进行隐式类型转换 A aa =1;//c++11中多参数的构造函数也可以进行隐式类型转换 B bb ={2,3};return0;}
运行结果如下,无报错成功
  1. 当然如果我们在类中不想要类型转换发生,可以使用explicit修饰对应成员函数即可限制类型转换
#include<iostream>usingnamespace std;classA{public:explicitA(int a):_a(a){}private:int _a;};classB{public:explicitB(int b,int c):_b(b),_c(c){}private:int _b;int _c;};intmain(){//隐式类型转换int a =0;double b = a;//单参数的构造函数可以进行隐式类型转换 A aa =1;//c++11中多参数的构造函数也可以进行隐式类型转换 B bb ={2,3};return0;}
运行结果如下

强制类型转换

  1. 显示的强制类型转换:需要用户使用 () 手动进行转换,强制类型转换近似关系的类型,例如指针和整形int之间,虽然指针和整形int是两种不同的类型,但是指针的本质是地址的编号,从小到大的地址进行编号,指针其实也是表示着数据的大小,整形int也是用于表示数据的大小,所以指针和整形int有近似关系,可以进行转换
intmain(){//强制类型转换int a =0;int* pa =nullptr; pa =(int*)a;return0;}
运行结果如下
  1. 当然如果是完全没有关系的两种类型那必然是不可以使用强制类型转换的,例如:string和vector之间是完全不相同的两种类型就不可以使用强制类型转换进行转换
intmain(){ string str; vector<int> v; str =(string)v;return0;}
运行结果如下,完全不同的类型无法进行强制类型转换

const常变量的强制类型转换

  1. 对于const修饰的变量称为常变量,它开了空间进行存储数据,由于被const进行修饰,所以变量具有常性,数据不可以进行修改,但是我们可以通过类型转换,通过地址解引用去修改它存储的数据的值,但是这种方式是不安全的,因为本质上我们使用const进行修饰变量,就是期望不进行修改数据
intmain(){//const常变量constint c =0;//这种转换方式是不安全的int* pc =(int*)&c;(*pc)++; cout << c << endl; cout <<*pc << endl;return0;}
运行结果如下
奇怪,小编不是取出常变量的地址,通过指针解引用的方式修改地址上存储的数据了吗?为什么这里的n和*pc的值却不一样,为什么n不是1?那么接下来小编调试带领大家看一下监视窗口,监视窗口显示的是实际内存中存储的值

那么继续执行语句,结果如下,???什么?在实际的内存中c修改成1了

那么继续执行语句,打印一下c,这你扯不扯,编译器给c打印的不是内存中的实际值,而是c最初值0

其实原因就是编译器认为这种取出常变量的地址,通过指针解引用的方式修改常变量的方式是不安全的,所以编译器对于访问打印常变量采用的方式是直接使用最初值进行替换或者常变量初始化的时候除了初始化常变量,并且还会一并将初始值放到寄存器中,当需要使用常变量的时候去寄存器中取常变量的初始值,不同的编译器实现可能不同
  1. 那么我们知道了这里为什么编译器打印c的值是初始值了,如果小编非要编译器取出变量的值的时候每次去内存里去取,那么就可以使用volatile关键字进行修饰变量,被volatile修饰的变量编译器在取它的值的时候,每次都会去内存中去取
intmain(){//const常变量volatileconstint c =0;//这种转换方式是不安全的int* pc =(int*)&c;(*pc)++; cout << c << endl; cout <<*pc << endl;return0;}
运行结果如下,编译器在取出常变量c的值的时候,去内存中去取c的值,而不是进行常变量初始值的替换或者去寄存器中去取常变量的初始值

总结

  1. c语言的转换很简单,但是仍然存在一些坑
  2. 隐式类型转换会出现精度缺失,程序如果不小心疏忽,会造成代码错误等
  3. 例如下面的函数fun本意是想要将形参的类型写成int,但是这里疏忽误写为了size_t,那么传参后,发生了我们未能察觉的隐式类型转换,while判断一直成立,如下代码就会陷入死循环
voidfun(size_t n){while(n >=0){ cout << n << endl; n--;}}intmain(){fun(5);return0;}
运行结果如下
  1. 显示类型转换,const类型转换和普通的强制类型转换不易区分
  2. 那么c++提出了自己的转换风格,可以有效的处理这些问题。由于c++兼容c语言,所以对于c++的转换只是一个建议,原有的c语言的转换仍然可以使用

二、c++的四种类型转换

c++引入了四种强制类型准换:分别是static_cast,reinterpret_cast,const_cast,dynamic_cast
下面小编将对这四种强制类型转换进行讲解

static_cast

static_cast也叫做静态转换,编译器执行的任何隐式类型转换都可以使用它,但是不能将它用于两种不相关的类型进行转换
intmain(){int a =0;double b =static_cast<double>(a);return0;}
运行结果如下,无误

reinterpret_cast

reinterpret_cast可以用于平替c语言中近似类型的强制类型转换,用于将一种类型强制转化为另一种近似关系的类型,但是reinterpret_cast不可以用于const类型的强制类型转换
intmain(){int a =0;int* pa =reinterpret_cast<int*>(a);return0;}
运行结果如下
intmain(){constint a =0;int* pa =reinterpret_cast<int*>(&a);return0;}
运行结果如下

const_cast

const_cast用于const类型的强制类型转换,用于去掉常变量的const属性
intmain(){constint a =0;int* pa =const_cast<int*>(&a);return0;}
运行结果如下

dynamic_cast

dynamic_cast也叫做动态转换,用于将父类对象的指针或引用转换为子类对象的指针或引用dynamic_cast只能用于父类含有虚函数的类(父类和子类构成多态)dynamic_cast会先检查能否转换成功,如果不能转换成功,则返回nullptr
  1. 向上转换:子类的指针或引用转化为父类的指针或引用,这种转换也叫做切割,切片,由于赋值兼容规则,这种转换是天然支持的,不需要进行类型转换
  2. 向下转换:父类的指针或引用转化为子类的指针或引用(使用dynamic_cast进行转化是安全的)
  3. 我们知道父类的指针或引用是有可能指向子类的指针或引用的,此时进行向下转化无非就是将原来的子类的指针或引用转化给子类的指针或引用,这完全是可以的,没有问题的,所以此时转化就是安全的,那么dynamic_cast就会允许转化,会返回转化后的类型的指针或引用
  4. 我们知道父类的指针或引用也有可能指向父类的指针或引用,此时进行向下转化,就会将父类的指针或引用转化为子类的指针或引用,此时由于父类的指针或引用指向的对象中没有子类那一部分的成员函数,如果进行赋值除了将父类的指针或引用指向的父类对象的那一部分成员函数之外,也会一并将未知内存的内容也给给子类的指针或引用,这可就坑了,子类的指针或引用可以接收父类对象的那一部分这没问题,但是如果接收了未知内存的内容,那么进行访问,或进行操作会造成越界访问或者崩溃,所以dynamic_cast认为这是不安全的,所以就不会允许进行转换,会返回一个nullptr,用户接收nullptr之后可以进行判断是否转化成功
  5. 为什么dynamic_cast可以进行检查?父类中有虚函数,子类继承父类,父类和子类构造多态,那么此时父类和子类就会有自己独特的一张虚函数表,编译器会在虚函数表中做一些独属于父类和子类自己的标记,dynamic_cast进行检查的时候会去对应对象的虚函数表中去检查这个标记来判断是这个对象指向的究竟是父类对象还是子类对象,进而就可以进行检查了
  6. 我们传入父类的指针,看能否进行转换
classA{public:virtualvoidf(){}};classB:publicA{};voidfun(A* a){ B* b =dynamic_cast<B*>(a);if(b ==nullptr){ cout <<"转换失败"<< endl;}else{ cout <<"转换成功"<< endl;}}intmain(){ A a;fun(&a);return0;}
运行结果如下
  1. 我们传入子类的指针,看能否进行转换
classA{public:virtualvoidf(){}};classB:publicA{};voidfun(A* a){ B* b =dynamic_cast<B*>(a);if(b ==nullptr){ cout <<"转换失败"<< endl;}else{ cout <<"转换成功"<< endl;}}intmain(){ B b;fun(&b);return0;}
运行结果如下

三、RTTI

RTTI(Run-time Type identification)也叫做运行时类型检查
c++通过以下几种方式都是运行时类型检查去支持RTTI
  1. typeid,用于打印变量的类型
  2. decltype,用于识别类型,进行定义变量
  3. dynamic_cast,用于将父类的指针或引用转化为子类的指针或引用

总结

以上就是今天的博客内容啦,希望对读者朋友们有帮助
水滴石穿,坚持就是胜利,读者朋友们可以点个关注
点赞收藏加关注,找到小编不迷路!

Read more

金三面了两家大厂前端岗,还没offer的可以试试我的方法(文档含答案)

前言:前所未有的挑战与机遇 2026年的前端面试,早已不再是刷几套“八股文”就能轻松过关的年代。如果你正准备冲击“金三银四”的大厂Offer,首先需要清醒地认识到:市场对前端工程师的定义正在被AI和行业寒冬彻底重塑。 当前,AI工具已能完成前端60%以上的基础页面构建工作,企业对初级岗位的需求急剧萎缩,而留下的岗位则对候选人提出了近乎严苛的要求。大厂前端岗的面试难度,已经从考察“你会不会写代码”,彻底转向了考察“你能否解决AI解决不了的复杂问题”以及“你是否具备从0到1搭建和维护系统的能力” 。这份《26年金三大厂前端岗面试1000道高频面试原题(含答案)》,正是基于这一背景,为你揭示高难度面试背后的真实逻辑。 一、难度升级:面试考察的三个维度转型 1. “八股文”消亡,场景题与架构设计成为主流 如果你还停留在背诵var和let区别的阶段,大概率会在初面就折戟沉沙。根据近期面试复盘,几乎没有大厂再单纯问语法细节,取而代之的是清一色的项目场景题。例如: * 性能优化: “当QPS达到峰值时,前端该如何处理?” “如何统计长任务时间并保证页面不卡顿?” 复杂场景实现: “

By Ne0inhk
前端异常捕获与统一格式化:从 console.log(error) 到服务端上报

前端异常捕获与统一格式化:从 console.log(error) 到服务端上报

🧑 博主简介:ZEEKLOG博客专家,「历代文学网」(公益文学网,PC端可以访问:https://lidaiwenxue.com/#/?__c=1000,移动端可关注公众号 “ 心海云图 ” 微信小程序搜索“历代文学”)总架构师,首席架构师,也是联合创始人!16年工作经验,精通Java编程,高并发设计,分布式系统架构设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。 🤝商务合作:请搜索或扫码关注微信公众号 “ 心海云图 ” 前端异常捕获与统一格式化:从 console.log(error) 到服务端上报 引言 在前端开发中,异常监控是保证应用稳定性的重要一环。当用户遇到页面白屏、功能不可用等问题时,如果能及时收集到详细的错误信息(包括堆栈、

By Ne0inhk
GoWeb必备理论

GoWeb必备理论

关于goweb,你不得不知道的知识 若是初学者可以借鉴GoWeb查阅本文。 HTTP状态码: 意义 每个状态码都是,http设计者对“网络通讯”中可能出现的情况的假设、预判。他就相当于现实世界的信号灯,就像大家一遇到404,就知道资源找不到了。一遇到500就知道服务器挂了。这种共识,也就是如今万维网的高效率的基础之一。 http状态码是日常开发,修改bug,的居家必备神器。咱们对常见状态码做了分类。 1、必须掌握的状态码 200 ok 最常见的状态码,代表请求完全正确,比如打开网页、调用api啥的。 301 moved permanently 资源永久迁移(例:访问时a.com会被从定项到b.com) 302 Found (部分资源,临时迁移) 400 Bad request(请求出错,参数缺少什么的..) 401 unauthorized(没有登入) 403 forbidden(

By Ne0inhk
【C/C++算法】从浅到深学习--- 简单模拟算法(图文兼备 + 源码详解)

【C/C++算法】从浅到深学习--- 简单模拟算法(图文兼备 + 源码详解)

绪论:冲击蓝桥杯一起加油!! 每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry” 绪论 : 本篇是一些简单的模拟算法,其中模拟的本质就是就是根据题目意思进行代码的实现,因为本质较为简单所以本章分析也较少,将会通过 5 题进行模拟算法的认识。 ———————— 早关注不迷路,话不多说安全带系好,发车啦(建议电脑观看)。 模拟算法: 比葫芦画瓢 特点: 1. 思路比较简单 2. 考察代码能力 流畅: 1. 模拟算法流程(一定不要空想,而是要草稿纸上过流程) 2. 把流程转化成代码 具体训练: 1. 替换所有的问号 题目: 分析题目并提出,解决方法: 题解核心逻辑: classSolution{public: string modifyString(string s){//较为简单直接根据题意模拟即可/

By Ne0inhk