C/C++语言基础--C++四大类型转换讲解

news2024/10/18 20:28:30

本专栏目的

  • 更新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";
    else
    	cat->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,就不单单只是加个负号这么简单了,这个本人会更新后面会更新《深入理解计算机系统》这本书学习笔记,到时候会有详细的讲解🔈。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2217997.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysql底层原理详细剖析

1. 索引数据结构 索引是帮助mysql 是帮助数据排序 且高效获取数据的数据结构 索引的数据结构有&#xff1a; 二叉树红黑树hash表b树 1.1 二叉查找树 二叉查找树 如果要查找&#xff0c;通过二分查找的复杂度进行查找数据&#xff0c;确实优化了性能&#xff0c;减少了io的…

【中危】Oracle TNS Listener SID 可以被猜测

一、漏洞详情 Oracle 打补丁后&#xff0c;复测出一处中危漏洞&#xff1a;Oracle TNS Listener SID 可以被猜测。 可以通过暴力猜测的方法探测出Oracle TNS Listener SID&#xff0c;探测出的SID可以用于进一步探测Oracle 数据库的口令。 建议解决办法&#xff1a; 1. 不应该使…

机器学习—特性缩放

特性缩放的技术能使梯度下降运行得更快&#xff0c;让我们先来看看功能大小之间的关系&#xff0c;这就是该特性的数字和相关参数的大小&#xff0c;作为一个具体的例子&#xff0c;让我们用两个特征来预测房子的价格&#xff0c;X1代表一个房子的大小&#xff0c;X2代表两个卧…

python爬取themoviedb电影网站信息

python爬取themoviedb电影网站信息 一、寻找数据接口二、解析主页数据,获取详情页url三、向详情页url发送请求、获取并解析数据四、完整代码一、寻找数据接口 打开网站首页,F12打开开发者工具,刷新页面。 向下滑动页面,点击页面上的“Load More”图标。 寻找到数据接口,…

掘金2.计算位置 x 到 y 的最少步数(简单01)

public class Main {public static int solution(int xPosition, int yPosition) {int diff (yPosition - xPosition);// 计算差值if(diff < 0)diff * -1;int steps 0; // 初始化步数int begin 0;// 初始化当前位置int step 1;//初始化步长// 循环直到到达目标位置while…

DSVPN简介与应用

目录 简介 DSVPN 封装模式 Nomal&#xff08;动态&#xff09;方式建立DSVPN 一、配置缺省包过滤 二、划分区域&#xff08;以总部为例&#xff09; 三、配置IP地址&#xff08;以R1为例&#xff09; 四、配置DSVPN 简介 DSVPN DSVPN&#xff08;Dynamic Secure Vir…

一种3D打印跑车模型LED安全夜灯

我学习入门单片机及3Dmax的副产品&#xff0c;小玩意。MCU用8脚的就好&#xff0c;多脚功能复用&#xff0c;涉及长短按中断、ADC、掉电唤醒及LED切换控制&#xff0c;硬件的充放电监控及光控等等麻雀虽小五脏俱全。发使用指南不是广告&#xff0c;感觉这样才能毫无遗漏的说明其…

动态规划(1)斐波那契数列模型

动态规划算法流程&#xff1a; 1、状态表示&#xff1a; 指的是dp&#xff08;dynamic programming&#xff09;表里面的值所表示的含义 如何得出&#xff1a;1、题目要求 2、经验题目要求 3、分析问题的过程中发现重复子问题 2、状态转移方程 dp[i]等于什么 3、初始化 保证…

RAG拉满-上下文embedding与大模型cache

无论怎么选择RAG的切分方案&#xff0c;仍然切分不准确。 最近&#xff0c;anthropics给出了补充上下文的embedding的方案&#xff0c;RAG有了新的进展和突破。 从最基础的向量查询&#xff0c;到上下文embedding&#xff0c;再到rerank的测试准确度都有了明显的改善&#xf…

【无标题】如何在Costura.Fody生成时排除掉某些dll

有个场景需要排除掉某些dll让他不要打包到exe中,这样做,修改FodyWeavers.xml

配合工具,快速学习与体验electron增量更新

有任何问题&#xff0c;都可以私信博主&#xff0c;共同探讨学习。 正文开始 前言一、如何使用源码1.1 下载代码1.2 下载资源1.3 运行项目 二、如何使用工具2.1 打包新版本更新包2.2 创建nginx文件服务器2.3 在文件服务器保存软件更新包 三、如何测试更新3.1本地运行低版本3.2 …

九、PESocket通信

知识点&#xff1a;高并发 1、下载PESocket 地址&#xff1a;PlaneZhong/PESocket: A C# Network Library. (github.com) 2、示例代码 发过去一个Hello&#xff0c;返回一个hello 当一个客户端关闭了&#xff0c;会出现一个提示 当一个客户端开启&#xff0c;会显示已连接 3…

运放类公式计算

简介 很多运放的GAIN采用dB的方式表达放大倍数&#xff0c;然而我们有时候习惯使用电压的倍数代表运放放大关系&#xff0c;本章主要简单介绍dB与电压转换的关系。 例如某运放的放大倍数如下&#xff1a; G1G2GAIN(dB)0029.60119.110131116 以上放大倍数我们无法知道输入的信号…

有趣的在线可视化网站:探索神经网络与矩阵运算

有趣的在线可视化网站&#xff1a;探索神经网络与矩阵运算 文章目录 有趣的在线可视化网站&#xff1a;探索神经网络与矩阵运算一 TensorFlow Playground 神经网络二 Symbolab 的矩阵迹计算器三 Matrixmultiplication 可视化教学工具 本文推荐了几个非常有趣且实用的在线可视化…

sql实战解析-sum()over(partition by xx order by xx)

该窗口函数功能 sum( c )over( partition by a order by b) 按照一定规则汇总c的值&#xff0c;具体规则为以a分组&#xff0c;每组内按照b进行排序&#xff0c;汇总第一行至当前行的c的加和值。 从简单开始一步一步讲&#xff0c; 1、sum( )over( ) 对所有行进行求和 2、sum(…

静态站点生成器哪家强?

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

【PhpSpreadsheet】ThinkPHP5+PhpSpreadsheet实现批量导出数据

目录 前言 一、安装 二、API使用 三、完整实例 四、效果图 前言 为什么使用PhpSpreadsheet&#xff1f; 由于PHPExcel不再维护&#xff0c;所以建议使用PhpSpreadsheet来导出exlcel&#xff0c;但是PhpSpreadsheet由于是个新的类库&#xff0c;所以只支持PHP7.1及以上的版…

如何激活Windows server服务器

步骤&#xff1a; 一、用VMware虚拟机安装了Windows server服务器之后的状态 图1-1 查看Windows server2019 系统信息 图1-2 在桌面上查看个性化&#xff0c;提示系统未激活 二、激活的步骤&#xff1a; 1.找激活工具 图1-2 寻找激活工具并准备拖拽到虚拟服务器中 2.解压…

【服务器虚拟化是什么?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

微信小程序使用MQTT连接阿里云

目录 一、新建项目和项目整体配置​ 二、MQTT 下载引入和配置连接​ 三、阿里云配置 1、创建产品及设备 2、数据进行云流转 四、创建 MQTT 连接​ 五、微信小程序配置 六、效果展示 1、微信小程序发送控制命令 2、LED台灯反馈LED状态 七、微信小程序项目完整代码 一…