【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

C++socket网络编程——udp服务器

C++socket网络编程——udp服务器

目录 一.端口号 VS  PID 二.套接字编程的类型 三.socket编程接口 四.基于udp的服务端和客户端全部代码 客户端 服务端 五.解释与运行 一些细节: 六.总结 一.端口号 VS  PID pid已经能够标识一台主机上的一个唯一一个进程了,为什么还需要端口号? 1. 不是所有的进程都需要网络通信,但是所有的进程都需要都pid; 2. 系统和网络功能解耦。         另外,一个进程可以绑定多个端口,但一个端口只能被一个进程绑定。         系统内定的端口号【0,1023】一般都要有固定的应用层协议使用,如http:80,https:443。 二.套接字编程的类型 1. 域间套接字编程——同一个机器内 2. 原始套接字编程——网络工具 3. 网络套接字编程—

By Ne0inhk
【C++哲学】面向对象的三大特性之 继承

【C++哲学】面向对象的三大特性之 继承

🔥拾Ծ光:个人主页 👏👏👏欢迎来到我的专栏:《C++》,《数据结构》,《C语言》 目录 一、继承的概念和定义 1、什么是继承? 2、继承的定义 2.1、定义格式 2.2、继承基类成员访问方式的变化 3、继承类模板 二、基类和派生类 1、基类与派生类间的类型转换⭐️ 2、继承中的作用域 2.1、隐藏规则 2.2、面试题实践⭐️ 三、派生类的默认成员函数 1、派生类4个常见的默认成员函数⭐️⭐️ 2、实现一个不能被继承的类 四、继承与友元 五、继承与静态成员 六、多继承及其菱形继承问题 1、继承模型 2、虚继承 3、

By Ne0inhk

Qt C++ 插件开发指南:插件架构设计与动态加载实战

一、Qt插件开发概述 1.1 插件技术核心价值 插件架构是一种软件设计模式,通过将应用程序的核心功能与扩展功能分离,允许第三方或开发者在不修改主程序源代码的情况下对软件进行功能扩展、特性升级或定制化改造。这种架构模式在大型软件系统中应用广泛,典型场景包括:IDE工具的插件扩展(如Qt Creator的插件体系)、图形软件的滤镜插件、办公软件的功能模块扩展等。 Qt作为成熟的C++跨平台框架,提供了一套完整的插件机制,其核心优势体现在: * 跨平台兼容性:Qt插件可在Windows、Linux、macOS等系统上统一构建和加载,无需针对不同平台编写适配代码; * 二进制级扩展:插件以动态链接库(.dll/.so/.dylib)形式存在,主程序与插件通过统一接口交互,无需重新编译主程序即可更新插件; * 低耦合设计:主程序仅依赖插件接口抽象,不关心具体实现,插件可独立开发、测试和部署; * 框架原生支持:Qt提供QPluginLoader、QObject、Q_INTERFACES等核心类和宏,简化插件注册、发现和通信流程。 1.2 Qt插件的两种类型 Qt插件体系主要分

By Ne0inhk