C++中的提供的四种类型转换方式;

news2024/11/7 4:05:50

C++中的提供的四种类型转换方式详解

目录

  • C++中的提供的四种类型转换方式详解
    • 前言
      • 1. `static_cast`
      • 2. `dynamic_cast`
        • 向上转型(派生类到基类)
        • 向下转型(基类到派生类)
        • 交叉转型(在多继承等复杂情况)
      • 3. `const_cast`
      • 4. `reinterpret_cast`

前言

在日常的代码编写中,我们经常会遇到有意识和没有意识的类型转换,而直接用C语言提供的强行转换或者干脆是没有意识的隐式类型转换是不安全的,且容易造成一些难以排除的错误。

常见的隐式类型转换:

1、算术运算中的类型转换

整型提升:在进行算术运算时,charshort等较小的整型类型通常会被提升为int类型(如果int类型能够表示其值的范围)。例如:

char a = 5;
char b = 6;
int c = a + b; 

这里ab在执行加法运算时会被隐式提升为int类型,然后再进行计算,结果存储在int类型的c中。

  • 不同整型类型的混合运算:当不同大小的整型类型(如intlong)进行算术运算时,编译器会将较小的类型转换为较大的类型,以避免数据丢失。例如:

  • double d = 3.14;
    int i = d; 
    
  • 这里int类型的i被隐式转换为double类型,然后赋给d

2、赋值运算中的类型转换

将较小类型的值赋给较大类型的变量:当把一个值赋给一个能容纳更大范围值的变量时,会自动进行类型转换。

将较大类型的值赋给较小类型的变量(可能导致数据丢失):如果将一个较大类型的值赋给一个较小类型的变量,并且该值在较小类型的表示范围内,则进行隐式转换,可能会截断数据。

3、函数调用中的类型转换

参数传递:当函数参数的类型与传入的值类型不完全一致时,如果可以进行隐式转换,编译器会自动进行转换。

4、初始化中的类型转换

初始化对象时的类型转换:在初始化一个变量或对象时,如果初始化值的类型与被初始化对象的类型不同,但存在合适的隐式转换关系,则会进行转换。

5、布尔值转换

在 C++ 中,整数类型、指针类型等可以隐式转换为布尔值。非零值转换为true,零值转换为false

而c++提供了四种标准的类型转换,极大程度上解决了这些不确定性。

1. static_cast

static_cast用于在相关类型之间进行转换,这些类型在概念上是相关的,编译器在大多数情况下可以隐式执行的类型转换都可以用static_cast显式完成。例如,基本数据类型之间的转换,像intfloat之间

int i = 10;
float f = static_cast<float>(i); 
  • 用于类层次结构中的转换
    在类层次结构中,static_cast可用于向上转型(将派生类指针或引用转换为基类指针或引用),这是一种安全的转换,因为派生类对象包含了基类的所有信息。
class Base {};
class Derived : public Base {};
Derived d;
Base* b = static_cast<Base*>(&d); 

局限性
它不能用于在不相关的类型之间进行转换,比如将一个指针转换为一个完全不相关类型的指针,而且它不进行运行时类型检查,对于向下转型(将基类指针或引用转换为派生类指针或引用)可能存在风险,如果转换的对象不是期望的派生类类型,会导致未定义行为。

常见的相关类型:

1、整型之间

2、枚举类型与整型

3、指针和 void*

4、具有相同底层表示的类型:如:

struct StructA {
    int value;
};

struct StructB {
    int anotherValue;
};

StructA a = { 5 };
StructB b = static_cast<StructB>(a); 

5、有继承关系的类

在 C++ 中,不同类型的指针在特定平台上其大小可能是相同的(比如在 32 位系统中指针通常是 4 字节,在 64 位系统中通常是 8 字节),但它们所指向的对象类型和内存布局含义完全不同。static_cast不能用于在两个没有关系的指针类型之间进行转换。

static_cast的转换规则限制
static_cast是基于类型兼容性进行转换的,对于指针类型,它主要用于在类层次结构中的向上转型(安全的,因为派生类包含基类的所有信息)以及相关类型指针之间有意义的转换(比如void*与其他类型指针在符合逻辑的情况下)。如果试图使用static_cast在两个完全不相关的指针类型(如int*double*)之间转换,编译器会报错,因为这种转换不符合static_cast所遵循的类型规则。

2. dynamic_cast

dynamic_cast主要用于在类的继承层次结构中进行安全的和向上向下转型或交叉转型(在多继承情况下)。它在运行时检查对象的类型信息。

向上转型(派生类到基类)

转换规则:在向上转型时,dynamic_cast可以像static_cast一样将派生类指针或引用安全地转换为基类指针或引用。因为派生类包含了基类的所有信息,这种转换总是成功的(只要类型正确)。例如:

class Base { virtual void foo() {} };
class Derived : public Base {};

Derived d;
Base* b = dynamic_cast<Base*>(&d); 

这里b成功指向d对象,因为DerivedBase的派生类,这种转换是多态类型安全的,即使没有使用dynamic_cast,使用static_cast也能完成,但dynamic_cast在这种情况下会在运行时检查类型信息(虽然这里向上转型一定成功,但它遵循运行时检查机制)。

向下转型(基类到派生类)

转换规则:当进行向下转型时,dynamic_cast会在运行时检查被转换对象的实际类型。只有当基类指针或引用实际指向的是目标派生类类型(或其派生类)的对象时,转换才会成功。如果是指针类型,转换失败会返回nullptr;如果是引用类型,转换失败会抛出std::bad_cast异常。例如:

class Base { virtual void foo() {} };
class Derived : public Base {};

Base* b = new Derived;
Derived* d = dynamic_cast<Derived*>(b); // 成功,因为b实际指向Derived对象

Base* basePtr = new Base;
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); // 失败,返回nullptr(指针类型)
try {
    Derived& derivedRef = dynamic_cast<Derived&>(*basePtr); // 失败,抛出std::bad_cast异常(引用类型)
} catch (const std::bad_cast& e) {}

应用场景:这种运行时类型检查机制使得在复杂的类层次结构中,可以安全地进行向下转型操作,尤其是当通过基类指针或引用操作对象,但在某些情况下需要访问派生类特有的成员或功能时非常有用。

交叉转型(在多继承等复杂情况)

转换规则:在多继承的情况下,dynamic_cast也能正确处理复杂的类型转换。例如,有类Base1Base2Derived,其中Derived同时继承自Base1Base2

class Base1 { virtual void foo1() {} };
class Base2 { virtual void foo2() {} };
class Derived : public Base1, public Base2 {};

Base1* base1Ptr = new Derived;
Base2* base2Ptr = dynamic_cast<Base2*>(base1Ptr); 
// 如果base1Ptr实际指向Derived对象,可以成功转换到Base2*,利用了运行时类型信息和多继承的内存布局

重要性:这在处理复杂的类关系和对象类型不确定的情况下,能保证类型转换的安全性和正确性,避免了对内存中对象的错误访问。

所以,dynamic_cast主要用于处理类层次结构中的类型转换,无论是向上转型、向下转型还是在多继承等复杂场景下的交叉转型,都利用了其运行时类型检查的特性来确保安全。

  • 用于多态类型的检查
    如果dynamic_cast的目标类型是指针类型,并且转换失败,它会返回nullptr;如果目标类型是引用类型,并且转换失败,它会抛出std::bad_cast异常。这使得在处理类层次结构中的对象时,可以更安全地确定对象的实际类型。
  • 局限性
    dynamic_cast只能用于包含虚函数的类层次结构中,因为它依赖于运行时类型信息(RTTI),而 RTTI 是通过虚函数表来实现的。对于非多态类型(没有虚函数的类),不能使用dynamic_cast

3. const_cast

const_cast用于去除或添加constvolatile限定符。它主要用于在函数中,当一个参数被声明为const,但函数内部需要修改这个值的情况(这种情况通常表明设计可能存在问题,但在某些特定场景下有其用途)。例如:

void func(const int* ptr) {
    int* non_const_ptr = const_cast<int*>(ptr);
    *non_const_ptr = 10; 
}

注意事项
使用const_cast去除const限定符并修改const对象的值是一种危险的操作,可能会导致未定义行为,尤其是当这个const对象在其他地方被期望保持不变时。只有当确定对象最初不是const,只是在当前指针或引用的限定中有const修饰时才能安全使用。

4. reinterpret_cast

reinterpret_cast是一种较为危险的类型转换操作符,它可以将一种类型的指针转换为另一种完全不同类型的指针,或者将一个整数转换为指针,反之亦然。例如:

int i = 10;
void* ptr = reinterpret_cast<void*>(&i); 
// 将int* 转换为void*

用于特殊的内存操作(谨慎使用)
在一些底层编程中,比如与硬件交互或者实现特定的内存布局操作时可能会用到。但这种转换几乎不进行任何类型检查,很容易导致程序出现严重的错误,如内存访问违规、数据损坏等。例如,将一个指向char数组的指针reinterpret_cast为一个指向复杂结构体的指针并访问,可能会破坏内存中数据的原有含义。

reinterpret_cast本身不保证安全,使用它时需要程序员对所涉及的底层机制(如硬件、内存布局、数据表示等)有深入了解,并经过仔细的设计和验证,以尽量避免可能出现的错误。它是一种强大但极具危险性的工具,应谨慎使用。

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

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

相关文章

Ceisum无人机巡检视频投放

公司投标内容有个视频投放的功能动画&#xff0c;原本想实现这么一个效果&#xff1a; 案例效果来自别人的展示作品&#xff0c;Leader一眼就相中了这个效果&#xff0c;可惜别人的终究是别人的&#xff0c;又不会白白给你&#xff0c;终究是要自己动手尝试。 动画方面的展示…

Spring:Bean(创建方式,抽象继承,工厂Bean,生命周期)

1&#xff0c;Bean的创建 1.1&#xff0c;调用构造器创建Bean 调用Bean类的无参构造函数来创造对象&#xff0c;因此要求提供无参构造函数。在这种情况下class元素是必须的&#xff0c;值就是Bean对象的实现类。 如果采用设值注入&#xff0c;Spring容器将使用默认的构造器来创…

ViT面试知识点

文章目录 VITCLIPBlipSAMLSegFast TransformerYOLO系列问题 BatchNorm是对一个batch-size样本内的每个特征做归一化&#xff0c;LayerNorm是对每个样本的所有特征做归一化。 Layer Normalization&#xff08;层归一化&#xff0c;简称LayerNorm&#xff09;是一种在深度学习中…

了解数据库并发产生的问题

在数据库管理系统中&#xff0c;并发控制是一个至关重要的方面。随着多个用户或进程同时访问和修改数据库中的数据&#xff0c;如果没有适当的并发控制机制&#xff0c;就可能导致数据不一致、丢失更新、脏读、不可重复读和幻读等问题。在单用户系统中&#xff0c;数据库操作是…

qt QFontDialog详解

1、概述 QFontDialog 是 Qt 框架中的一个对话框类&#xff0c;用于选择字体。它提供了一个可视化的界面&#xff0c;允许用户选择所需的字体以及相关的属性&#xff0c;如字体样式、大小、粗细等。用户可以通过对话框中的选项进行选择&#xff0c;并实时预览所选字体的效果。Q…

【JavaSE】(2) 方法

一、认识方法 1. 方法的定义 修饰符 返回类型 方法名(形参类型 形参名, ......){......return 返回值; } 示例代码&#xff1a; 2. 方法的作用 增强代码的可复用性。&#xff08;避免重复造轮子&#xff09;增强代码的易管理性。&#xff08;改方法就行&#xff0c;不用到处…

享元模式及其运用场景:结合工厂模式和单例模式优化内存使用

介绍 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过共享对象来减少内存使用&#xff0c;尤其是对于大量相似对象的场景。享元模式通常与工厂模式和单例模式结合使用&#xff0c;从而有效地控制和复用对象的创建。在享元模式中&am…

【RabbitMQ】03-交换机

1. 交换机 2. Fanout交换机 广播。生产者向exchange发消息 SpringBootTest public class SpringAmqpTest {Autowiredpublic RabbitTemplate rabbitTemplate;Testvoid testSimple() {String exchangName "hmall.fabout";rabbitTemplate.convertAndSend(exchangName…

【赵渝强老师】安装部署Memcached

Memcached是一个高性能的分布式的内存对象缓存系统。通过使用Memcached可以支持高负载的网站系统&#xff0c;以分担数据库的压力。Memcached通过在内存里维护一个统一的巨大的Hash表来存储各种格式的数据&#xff0c;包括图像、视频、文件以及数据库检索的结果等。但是Memcach…

代码要走的路:编程“三部曲”

代码要成为可以运行的程序&#xff0c;总共有3步&#xff1a; 1&#xff0e;编辑&#xff08;edit&#xff09; 这里的编辑不是像出版编辑那样&#xff0c;只把现成的东西修修改改&#xff0c;而是指编写代码。 编写代码是实实在在的原创&#xff0c;不是整理加工&#xff0…

支持向量机相关证明 解的稀疏性

主要涉及拉格朗日乘子法&#xff0c;对偶问题求解

漫途焊机安全生产监管方案,提升安全生产管理水平!

随着智能制造时代的到来&#xff0c;企业安全生产管理的重要性日益凸显。特别是在现代工厂中&#xff0c;焊机的安全生产监管成为了一个不容忽视的重要环节。传统的焊机安全生产监管方式存在诸多不足&#xff0c;如人工巡检频率低、数据延迟、安全隐患发现不及时等问题。因此&a…

【dvwa靶场:XSS系列】XSS (Reflected)低-中-高级别,通关啦

一、低级low 简单拿捏 <script>alert(123)</script>二、中级middle 源码过滤了script但是没有过滤大小写&#xff0c;改成大写S <Script>alert(123)</script>三、高级high 比中级高&#xff0c;过滤了script并且以及大小写&#xff0c;使用其他标…

太速科技-634-基于3U PXIe的VU3P FMC+数据接口板

基于3U PXIe的VU3P FMC数据接口板 一、产品概述 板卡是一款基于 3U PXIE 总线架构的高性能数据预处理FMC 载板&#xff0c;具有 1 个 FMC&#xff08;HPC&#xff09;接口&#xff0c;1 个 X8 GTH 背板互联接口&#xff0c;可以实现 1 路 PCIe x8。板卡主控芯片采用Xilin…

【LLM Agents体验】Dify框架的安装指南

Dify简介&#xff1a; 核心功能‌12 ‌Dify是一款开源的大语言模型(LLM)应用开发平台&#xff0c;融合了后端即服务&#xff08;Backend as a Service, BaaS&#xff09;和LLMOps的理念&#xff0c;使开发者可以快速搭建生产级的生成式AI应用。LLMOps涵盖了大型语言模型的开发、…

推荐一款PowerPoint转Flash工具:iSpring Suite

iSpring Suite是一款PowerPoint转Flash工具&#xff0c;使用iSpring Suite 8可以轻松的将PPT演示文档转换为对Web友好的Flash影片格式。软件界面简洁&#xff0c;使用方便。为什么要转换成flash格式呢?Flash格式的最大特点是体积小巧、易于分发&#xff0c;兼容所有的操作系统…

数据库->视图

目录 一、视图 1.什么是视图 ​编辑 2.创建视图 1.语法 3.使用视图 4.视图的功能 1.屏蔽相关字段 2.对外提供统一访问规范 3.视图和真实表进行表连接查询 5.修改数据 6.注意事项 7.删除视图 1.语法 8.视图的优点 1. 简单性 2. 安全性 3. 逻辑数据独⽴性 4. 重…

影响神经网络速度的因素- FLOPs、MAC、并行度以及计算平台

影响神经网络速度的四个主要因素分别是 FLOPs&#xff08;浮点操作数&#xff09;、MAC&#xff08;内存访问成本&#xff09;、并行度以及计算平台。这些因素共同作用&#xff0c;直接影响到神经网络的计算速度和资源需求。 1. FLOPs&#xff08;Floating Point Operations&a…

Java Development Kit (JDK) 详解

什么是 JDK&#xff1f; JDK 是 Java Development Kit 的缩写&#xff0c;是一组用于开发 Java 应用程序的软件开发工具和库的集合。JDK 包含了 Java 运行时环境&#xff08;JRE&#xff09;和 Java 虚拟机&#xff08;JVM&#xff09;&#xff0c;以及一系列开发工具和库。 …

Rust 力扣 - 1652. 拆炸弹

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们只需要遍历长度长度为k的窗口&#xff0c;然后把窗口内数字之和填充到结果数组中的对应位置即可 题解代码 impl Solution {pub fn decrypt(code: Vec<i32>, k: i32) -> Vec<i32> {let n c…