类型转换——C++

news2025/1/18 7:37:04

1. C语言中的类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,
C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。

  1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
  2. 显式类型转化:需要用户自己处理

在C语言中:
整型之间的转换:大转小——截断;小转大——提升
整型与浮点之间的转换:补位
意义相近的类型:例如浮点和整型,因为它们互相之间都是用来表示数据的大小

 

void Test1()

{
    int i = 1;
    // 隐式类型转换(意义相近的类型)
    double d = i;
    printf("%d, %.2f\n", i, d);

    int* p = &i;
    // 显示的强制类型转换(意义不相近,但是值转换后有意义)
    int address = (int)p;
    printf("%x, %d\n", p, address);
}

缺陷:转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换

 

//在pos位置插入一个字符
void Insert(size_t pos, char ch)
{
    size_t end = size - 1;
    while (end >= pos)
    {
        _str[end + 1] = -str[end];
        --end;
    }
}

问题:调用的时候
Insert(2,‘a’);//没问题
Insert(0,‘a’);//会死循环
隐式类型转换在操作符的两边也会发生:while (end >= pos)
将-1就会提升为无符号位的整型最大值,访问数据就会发生越界

 

 

2. 为什么C++需要四种类型转换

C语言风格的转换格式很简单,但是有不少缺点的:

  1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
  2. 显式类型转换将所有情况混合在一起,代码不够清晰
    因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格

 
 

3. C++强制类型转换

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:
static_cast、reinterpret_cast、const_cast、dynamic_cast

  1. 兼容C语言的隐式类型转换和强制类型转换
  2. 虽然兼容c但是最好不用,使用C++的强制类型转换更加规范
  3. static_cast(影视类型转换)、reinterpret_cast、const_cast(强制类型转换)

 
 

3.1 static_cast

用于意义相近的类型
static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用
static_cast,但它不能用于两个不相关的类型进行转换

int main()
{
double d = 12.34;
int a = static_cast<int>(d);
cout<<a<<endl;
return 0;
}

在这里插入图片描述

注意写法与括号。
不是意义相近类型是无法使用此方法的

 

3.2 reinterpret_cast

不相关类型的转换
reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型

int main()
{

    int* p = &a;
    //int address = static_cast<int>(p);
    int adress = reinterpret_cast<int>(p);
    return 0;
}
甚至可以支持一些比较bug的转换:
int main()
{
double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl;
// 这里使用static_cast会报错,应该使用reinterpret_cast
//int *p = static_cast<int*>(a);
int *p = reinterpret_cast<int*>(a);
return 0;
}

 

3.3 const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值

int main()
{
    const int a = 2;
    int* p = const_cast< int*>(&a);//a的地址给了p
    *p = 3;
    cout << a << endl;//2
    cout << *p << endl;//3
}

使用调试的方法:
添加断点
Ctrl+f10 开始调试
打开监视窗口,输入你想观察的变量名称
按f10,程序就会依次往下执行

监视窗口中是3和3,但打印出来就是2和3
在这里插入图片描述

原因:编译器对const类型有优化,因为它理论上认为const类型不会被修改。const类型不会在内存中取,会被加载到寄存器中
每个不同的编译器,优化方法可能会不一样

 

有方法可以解决吗?
关键字 volatile
在这里插入图片描述

 
 

3.4 dynamic_cast

C++独有的

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)——天然支持的
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)

注意:

  1. dynamic_cast只能用于父类含有虚函数的类
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0

类型转换无论是否规范都会产生临时变量
临时变量具有常性——要用const

int main()
{
    int i = 0;
    double d = i;

    const double& rd1 = i;
    const double& rd2 = static_cast<double>(i);

    return 0;
}

 

注意:父类对象无论如何都不允许转成子类对象的。
指针,引用都允许转换

class A
{
public:
    virtual void f(){}
public:
    int _a = 0;
};

class B : public A
{
public:
    int _b = 1;
};

// A*指针pa有可能指向父类,有可能指向子类
void fun(A* pa)
{
    // 如果pa是指向子类,那么可以转换,转换表达式返回正确的地址
    // 如果pa是指向父类,那么不能转换,转换表达式返回nullptr
    B* pb = dynamic_cast<B*>(pa); // 安全的
    //B* pb = (B*)pa;             // 不安全,都是转换成功无法识别,会产生越界的风险
    if (pb)
    {
        cout << "转换成功" << endl;
        pb->_a++;
        pb->_b++;
        cout << pb->_a << ":" << pb->_b << endl;
    }
    else
    {
        cout << "转换失败" << endl;
        pa->_a++;
        cout << pa->_a << endl;
    }
}

int main()
{
    A aa;
    // 父类对象无论如何都是不允许转换成子类对象的
    /*B bb = dynamic_cast<B>(aa);
    B bb = (B)aa;*/
    B bb;

    fun(&aa);
    fun(&bb);
    //fun(nullptr);

    return 0;
}

在这里插入图片描述

 

延伸问题:

class A1
{
public:
    virtual void f(){}
public:
    int _a1 = 0;
};

class A2
{
public:
    virtual void f(){}
public:
    int _a2 = 0;
};

class B : public A1, public A2
{
public:
    int _b = 1;
};

int main()
{
    B bb;
    A1* ptr1 = &bb;
    A2* ptr2 = &bb;
    cout << ptr1 << endl;
    cout << ptr2 << endl << endl;

    B* pb1 = (B*)ptr1;
    B* pb2 = (B*)ptr2;
    cout << pb1 << endl;
    cout << pb2 << endl << endl;

    B* pb3 = dynamic_cast<B*>(ptr1);
    B* pb4 = dynamic_cast<B*>(ptr2);
    cout << pb3 << endl;
    cout << pb4 << endl << endl;

    return 0;
}

切片会偏移,所以ptr1和ptr2的地址不一样
在这里插入图片描述

 
但是强制类型转换之后指针会偏移回去
在这里插入图片描述

 
注意:
强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会。强烈建议:避免使用强制类型转换

 

4. RTTI(了解)

RAII 资源获取就是初始化
RTTI:Run-time Type identification的简称,即:运行时类型识别。
C++通过以下方式来支持RTTI:

  1. typeid运算符——获取对象类型字符串
  2. dynamic_cast运算符——父类的指针指向父类对象还是子类对象
  3. decltype——推导一个对象类型,这个类型可以用来定义另一个对象

 
 

5. 常见面试题

  1. C++中的4中类型转化分别是:
  2. 说说4中类型转化的应用场景。

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

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

相关文章

刘二大人《Pytorch深度学习实践》第十讲卷积神经网络(基础篇)

文章目录卷积神经网络基础卷积层池化层课上代码GPU版本代码卷积神经网络基础 全连接的网络将图片的的本身二维空间结构进行了破坏&#xff0c;而这些空间结构是有用的&#xff0c;因此&#xff0c;要定义新的操作图像的计算节点&#xff0c;因此引入了卷积神经网络&#xff0c;…

JavaWeb开发 —— 请求响应

目录 一、概述 二、请求 1. postman工具 2. 简单参数 3. 实体参数 4. 数组集合参数 5. 日期参数 6. JSON参数 7. 路径参数 三、响应 1. ResponseBody 2. 统一响应结果 3. 案例 一、概述 通过之前对 JavaWeb开发 —— Web入门 的学习&#xff0c;我们开发…

失眠一月码出527页文档,详解SpringCloud微服务和分布式系统实践

所谓的分布式系统&#xff0c;就是一组计算机为了共同完成业务功能通过网络协作的多节点系统。分布式系统本身也有一系列需要解决的问题&#xff0c;包括多个计算机节点的路由选择、各个服务实例的管理、节点监控、节点之间的协作和数据一致性等&#xff0c;当然还有网络故障、…

lamp 架构的搭建

php 解释动态页面 php来连接数据库 mysql 页面信息和端口信息 存放数据 apache 前端web服务器&#xff0c;展现页面 源码编译安装这三个服务 配置下载apache: systemctl stop firewalld 关闭安全机制&#xff0c;防火墙 可以一条命令:systemctl is-enabled firewalld 和 s…

【推荐系统】model 落地(样本/特征/预测服务)

兜率宫小道童的个人空间-兜率宫小道童个人主页-哔哩哔哩视频&#xff08;如下是该视频课系列的笔记&#xff09; 1-深度学习在搜索、广告、推荐系统中的应用-业务问题建模_哔哩哔哩_bilibili 其他章节 目录 二、深度学习落地 模型训练服务流程 1-样本生成-标签拼接 1-样本…

OJ练习第73题——解数独

解数独 力扣链接&#xff1a;37. 解数独 题目描述 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一…

MySQL-中间件mycat(二)

目录 &#x1f341;部署主从复制 &#x1f341;mycat读写分离 &#x1f342;修改配置文件 &#x1f342;设置balance与writeType &#x1f342;设置switchType与slaveThreshold &#x1f342;启动程序 &#x1f342;验证读写分离 &#x1f341;垂直拆分-分库 &#x1f342;实现…

【从零开始学Skynet】基础篇(九):调试控制台服务

Skynet自带了一个调试控制台服务debug_console&#xff0c;启动它之后&#xff0c;可以查看节点的内部状态。 1、启用调试控制台 &#xff08;1&#xff09;在skynet/examples目录下新建main_console.lua文件&#xff0c;代码如下所示&#xff1a; local skynet require &quo…

【Python_Scrapy学习笔记(二)】创建Scrapy爬虫项目

创建Scrapy爬虫项目 前言 本文主要介绍如何创建并运行 Scrapy 爬虫项目。 正文 1、创建 Scrapy 框架 Scrapy 框架提供了 scrapy 命令用来建立 Scrapy 工程&#xff0c;在终端 terminal 中输入以下命令&#xff1a; scrapy startproject 自定义的项目名称创建好爬虫项目文件…

2023年超实用的27个VSCode插件推荐

Visual Studio Code&#xff0c;或者称作VS Code&#xff0c;是一个广为人知且评价很高的代码编辑器&#xff0c;它有许多特性和扩展功能&#xff0c;以增强开发体验。使用VS Code的主要好处之一是它的灵活性&#xff0c;允许开发人员根据自己的特定需求进行自定义。此外&#…

02-app漏洞发现

漏洞发现-APP应用之漏洞探针类型利用修复 一、思维导图&#xff1a; 思路说明&#xff1a; apk反编译提取URL或抓包获取url&#xff0c;进行web应用测试&#xff0c;如不存在或走其他协议的情况下&#xff0c;需采用网络接口抓包进行数据获取&#xff0c;转至其他协议安全测试…

【jvm系列-05】精通运行时数据区共享区域---方法区

JVM系列整体栏目 内容链接地址【一】初识虚拟机与java虚拟机https://blog.csdn.net/zhenghuishengq/article/details/129544460【二】jvm的类加载子系统以及jclasslib的基本使用https://blog.csdn.net/zhenghuishengq/article/details/129610963【三】运行时私有区域之虚拟机栈…

Redis 6.0的多线程是如何工作的

来了解下 6.0 版本中新出的多线程特性。 1、多线程处理网络IO&#xff0c;单线程执行命令 Redis 一直被大家熟知的就是它的单线程架构&#xff0c;虽然有些命令操作可以用后台线程或子进程执行&#xff08;比如数据删除、快照生成、AOF 重写&#xff09;&#xff0c;但是&…

freeswitch带媒体压力测试方案

概述 原本的计划是使用sipp完成带媒体压力测试&#xff0c;但是实际测试过程中发现sipp的媒体处理功能有问题&#xff08;也有可能是我使用的姿势不对&#xff09;。 sipp在带媒体的情况下&#xff08;600路并发开始&#xff09;&#xff0c;出现大量的不响应和响应延迟&…

请求响应-响应

前面已经说了我们重点关注的就是XXXcontroller类 进行请求接收 和响应 接收参数那些我们在请求部分讲过了 现在我们来处理响应部分 响应 设置响应数据 可以发现其实我们之前都是设置过的 比如那个Hello World 浏览器都接收到了且在浏览器上进行了输出 这里的是返回值作为这个…

Direct3D 12——纹理——纹理

纹理不同于缓冲区资源&#xff0c;因为缓冲区资源仅存储数据数组&#xff0c;而纹理却可以具有多个mipmap层级(后 文有介绍)&#xff0c;GPU会基于这个层级进行相应的特殊操作&#xff0c;例如运用过滤器以及多重采样。支持这些特殊 的操作纹理资源都被限定为一些特定的数据格式…

7 个最好的 Word 转 PDF 转换器

如果您使用 Word 文件&#xff0c;您可能在某个时候遇到过将 Word 文件转换为 PDF 的紧迫问题。PDF 文件有很多优点。它们通常更紧凑&#xff0c;无论您在哪里打开它们看起来都一样。PDF 还允许您共享文档&#xff0c;而不必冒有人更改内容的风险。那么如何将 Word 文档转换为 …

小白学网络安全要学些什么?

一.网络安全学些什么呢&#xff1f; 虽然网上已经有非常多的学习路线了&#xff0c;但是仍然有很多零基础的小白还是不懂网络安全到底应该要怎么去学习&#xff0c;我也经常会在后台收到这样的问题“我想学网络安全&#xff0c;需要先学编程语言吗&#xff1f;”、“学渗透就业…

【python零碎】

1. 拼接字符中&#xff0c;插入变量 >>> shepherd "Mary" >>> age 32 >>> stuff_in_string "Shepherd {} is {} years old.".format(shepherd, age) >>> print(stuff_in_string) Shepherd Mary is 32 years old. &…

HIT-CSAPP 第五章 面向程序的优化方法(1)

考纲: 1.面向程序性能的优化 面向编译器的程序优化方法:减少过程调用、减少内存引用、指令并行等方法等方法。面向流水线、超标量、向量CPU的程序优化方法。 2.存储器的层次结构 优化编译器的能力和局限性 内存别名使用妨碍函数优化 void twiddle1(long *xp, long *yp){ //…