[C++] 类型转换操作符(static_cast、dynamic_cast、const_cast、reinterpret_cast)

说明:本文主要解释static_cast、dynamic_cast、const_cast、reinterpret_cast这几种类型转换操作符。接下来我们对每一个类型转换操作符进行详细说明并给出一些基本的使用方式,重在深入理解。

在解释类型转换操作符之前,我们先了解下,为什么要引入类型转换操作符?

C语言本身就支持请值类型转换,那么C++为什么还要引入类型转换操作符呢,其实C++中引入类型转换操作符的设计目的是为了增强类型安全性和程序可靠性。相比C语言中的隐式类型转换和强制类型转换(例如,使用强制类型转换运算符),C++提供了更明确和可控的类型转换方式。设计类型转换操作符的主要目的具体解读如下:

  • 类型安全性:C++强调类型安全性,旨在减少类型错误和不正确的转换。类型转换操作符(如:static_cast、dynamic_cast、const_cast和reinterpret_cast)提供了更明确的转换语义和语法,使程序员能够更好地控制和理解转换的含义。
  • 可读性和可维护性:类型转换操作符使代码更具可读性和可维护性。通过使用具有明确名称的操作符,读者可以更容易地理解代码中的类型转换,而不需要深入理解C语言中的隐式转换规则或使用较为复杂的强制类型转换。
  • 编译时检查:类型转换操作符在编译时进行类型检查,以尽可能地捕获转换错误。相比C语言中的隐式转换和强制类型转换,C++的类型转换操作符提供了更多的编译时检查,可以帮助发现潜在的类型错误,减少运行时错误的可能性。
  • 安全性和可移植性:由于类型转换操作符提供了更多的类型检查和语义,它们通常比C语言中的强制类型转换更安全和可移植。C++的类型转换操作符在执行转换时会进行一些额外的检查和处理,以确保转换的安全性和可靠性。

总之,C++引入类型转换操作符的设计目的是为了提供更明确、可控和安全的类型转换方式,以增强类型安全性、代码可读性和可维护性,并减少类型错误和运行时错误的风险。详细来看,C++中的四种类型转换操作符(cast):static_cast、dynamic_cast、const_cast和reinterpret_cast,各自具有不同的设计目的,具体如下:

  • static_cast的设计目的:用于基本类型的转换、非多态类型之间的转换和具有继承关系的类型之间的转换。
  • dynamic_cast的设计目的:用于多态类型之间的转换,即涉及继承和虚函数的类型转换。
  • const_cast的设计目的:用于添加或移除常量性(const)和易变性(volatile)属性。
  • reinterpret_cast的设计目的:用于不同类型之间的强制类型转换,甚至是不相关类型之间的转换。

需要注意的是,强制类型转换(包括这四种转换操作符)应该慎用,因为它们可能引入类型不一致、未定义行为或安全隐患。在进行类型转换时,应该考虑转换的合理性和安全性,遵循良好的编程实践,并尽可能避免使用这些转换操作符。

接下来我们对四种类型转换操作符进行更详细的了解。

1 static_cast 类型转换操作符

static_cast可以用于隐式类型转换,也可以用于显式类型转换。它主要用于安全的类型转换,但不提供运行时检查。以下是一组示例,展示了static_cast的一些常见用法:

//正确用法
int a = 20;
long b = static_cast<long>(a);  //宽转换,没有信息丢失
char c = static_cast<char>(a);  //窄转换,可能会丢失信息,但是仍可以转换
int *p1 = static_cast<int*>( malloc(10 * sizeof(int)) );  //将void指针转换为具体int类型指针
void *p2 = static_cast<void*>(p1);  //将具体int类型指针转换为void指针
//错误用法
float *p3 = static_cast<float*>(p1);  //reinterpret_cast,但static_cast不可以在两个具体类型的指针之间进行转换
p3 = static_cast<float*>(0X3E4C);  //reinterpret_cast可以,但static_cast不能将整数转换为指针类型

2 dynamic_cast 类型转换操作符

dynamic_cast主要用于将指向基类的指针或引用转换为指向派生类的指针或引用。它在运行时进行类型检查,确保转换的安全性。如果指针或引用无法进行有效的转换,dynamic_cast将返回空指针(对于指针)或引发std::bad_cast异常(对于引用)。

2.1 dynamic_cast向上转型

只要待dynamic_cast转换的两个类型之间存在继承关系,并且基类包含虚函数,就一定能转换成功。因为向上转型始终是安全的,所以 dynamic_cast 不会进行任何运行期间的检查。以下是一组示例,展示了dynamic_cast的一些常见用法:

class Base {virtual void foo() {}
};class Derived : public Base {};int main()Derived *pd = new Derived();//父类引用指向子类对象,无问题,不进行RTTI检查Base *pb = dynamic_cast<Derived*>(pd);
}

但是注意,这里仅仅是判断两个类型之间存在继承关系,如果pd本身是其他类型转换过来的,即pd本身就是一个有问题的Derived *类型,那么转换出来的pb会是错误的。

2.2 dynamic_cast向下转型

向下转型是有风险的,dynamic_cast 会借助 RTTI 信息进行检测,确定安全的才能转换成功,否则就转换失败。以下是一组示例,展示了dynamic_cast的一些常见用法:

class A{
public:virtual void func() const { cout<<"func A"<<endl; }
};class B: public A{
public:virtual void func() const { cout<<"func B"<<endl; }
};class C: public B{
public:virtual void func() const { cout<<"func C"<<endl; }
};int main(){A *pa = new A();B *pb;pb = dynamic_cast<B*>(pa);  //向下转型失败pa = new C();pb = dynamic_cast<B*>(pa);  //向下转型成功return 0;
}

注意:

  • 本质上dynamic_cast只是支持向上转型的,即允许父类引用指向子类对象,不允许子类引用指向父类对象。所谓的向下转型,核心原因是以指向的对象类型为基础进行判定(从对象角度看,还是向上转型的),而不是仅仅以变量本身的类型来进行判定。
  • dynamic_cast需在运行时进行类型检查,相对于其他转换(比如:static_cast)来说会有一定的性能开销。

3 const_cast 类型转换操作符

const_cast主要用于去除对象的常量性或易变性,从而可以修改对象的值。它在类型转换时只修改常量性或易变性,不涉及对象的布局或位模式。以下是一组示例,展示了const_cast的一些常见用法:

示例 1:去除对象的常量性

void modifyValue(const int& value) {int& mutableRef = const_cast<int&>(value);mutableRef = 42;std::cout << "Modified value: " << value << std::endl;
}

在这个示例中,我们通过const_cast去除了value对象的常量性,并将其修改为42。尽管value被声明为常量引用,但通过使用const_cast,我们可以将其转换为可变引用,并修改其值。需要注意的是,这种修改实际上是违反了value的常量性。

示例 2:修改指向常量对象的指针

void modifyPointer(const int* constPtr) {int* mutablePtr = const_cast<int*>(constPtr);*mutablePtr = 42;std::cout << "Modified value: " << *constPtr << std::endl;
}

在这个示例中,我们有一个指向常量整数的指针constPtr,通过使用const_cast将其转换为指向非常量整数的指针mutablePtr,并修改了指针所指向的值为42。需要注意的是,这种修改同样是违反了constPtr指向对象的常量性。

示例 3:使用const_cast调用重载函数

class MyClass {
public:void doSomething() {std::cout << "Non-const doSomething()" << std::endl;}void doSomething() const {std::cout << "Const doSomething()" << std::endl;}
};int main() {const MyClass obj;const_cast<MyClass&>(obj).doSomething();  // 调用非常量版本的函数return 0;
}

在这个示例中,我们有一个类MyClass,其中包含了一个重载的成员函数doSomething(),分别针对非常量对象和常量对象。通过使用const_cast,我们可以将常量对象obj转换为非常量引用,并调用非常量版本的doSomething()函数。需要注意的是,这种用法可以破坏常量性,因此需要确保转换和调用的安全性。

4 reinterpret_cast 类型转换操作符

reinterpret_cast主要用于底层的位模式转换,例如将指针转换为整数或将整数转换为指针。这种转换是非类型安全的,需要谨慎使用。reinterpret_cast通常用于特殊情况,例如与底层硬件进行交互或进行类型擦除。以下是一组示例,展示了reinterpret_cast的一些常见用法:

示例 1:将指针转换为整数和逆转换

int* ptr = new int(42);
uintptr_t ptrValue = reinterpret_cast<uintptr_t>(ptr);
std::cout << "Pointer value: " << ptrValue << std::endl;int* ptrAgain = reinterpret_cast<int*>(ptrValue);
std::cout << "Pointer value after reinterpret_cast: " << *ptrAgain << std::endl;

在这个示例中,我们将指向int类型的指针转换为uintptr_t类型的整数,然后再通过reinterpret_cast将整数转换回指针。这种用法在需要将指针存储为整数或进行指针运算时可能会有用,注意:如果使用static_cast来转换不同类型的指针是错误的用法。

示例 2:将对象指针转换为基类指针

class Base {
public:virtual void foo() {}
};class Derived : public Base {
public:void foo() override {}
};Derived derivedObj;
Base* basePtr = reinterpret_cast<Base*>(&derivedObj);

在这个示例中,我们将指向派生类对象的指针转换为指向基类的指针。这种用法在需要处理多态类型的对象时可能会有用,但需要注意,reinterpret_cast不会进行运行时类型检查,因此使用时需要确保转换的安全性,dynamic_cast也可以实现该功能,这里只是使用示例来表达reinterpret_cast功能的强大。

示例 3:类型擦除

template <typename T>
void processData(T data) {void* erasedPtr = reinterpret_cast<void*>(&data);// ...
}

在这个示例中,我们使用reinterpret_cast将模板函数中的具体类型参数转换为void*,实现了类型擦除。这种用法在需要处理不同类型的数据,但又不关心其具体类型时可能会有用。

需要注意的是,reinterpret_cast是一种非常强大和危险的转换操作符,它涉及底层的位模式转换,因此使用时需要格外小心。在大多数情况下,应该优先考虑使用其他转换操作符,如static_cast或dynamic_cast,因为它们提供了更安全和类型正确的转换方式。只有在特定的情况下,且对类型的布局和位模式有深入了解时,才应该使用reinterpret_cast。

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

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

相关文章

AI大模型学习在数控系统工艺优化与智能制造中的应用

目录 1.工艺优化&#xff1a; 2.预测维护&#xff1a; 3.质量控制&#xff1a; 4.自动编程&#xff1a; 5.人机协作&#xff1a; 6.系统集成&#xff1a; AI大模型学习在数控系统工艺优化与智能制造中的应用主要体现在以下几个方面&#xff1a; 1.工艺优化&#xff1a; …

Java学习笔记 | Java基础语法 | 03 | 流程控制语句

文章目录 0 前言1.流程控制语句1.1 流程控制语句分类1.2 顺序结构 2.判断语句2.1 if语句1. if语句格式1练习1&#xff1a;老丈人选女婿练习2&#xff1a;考试奖励 2. if语句格式2练习1&#xff1a;吃饭练习2&#xff1a;影院选座 3. if语句格式3练习1&#xff1a;考试奖励 2.2 …

开源表单工作流引擎好用吗?

如果想提升办公协作效率&#xff0c;可以用什么样的平台软件实现&#xff1f;在竞争越来越激烈的社会中&#xff0c;想要实现高效率的办公&#xff0c;可以一起了解低代码技术平台以及开源表单工作流引擎。它们的易操作、灵活、简便等优势特点已成为了中小企业喜爱的优势特点。…

Kubernetes概念:工作负载:工作负载管理:1. Deployments

Deployments 官方文档&#xff1a;https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/deployment/ API&#xff1a;https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/workload-resources/deployment-v1/#Deployment 一个 Deployment 为 Pod 和 Repl…

2021保研夏令营面经 天大智算/同济软院/中山软件

天大智算 7月9-12日&#xff08;人太多排了3天&#xff09; 线上 面试 根据问卷里填报的实验室&#xff0c;一个人5分钟PPT&#xff0c;然后老师提问 Q1&#xff1a;你为什么想来天大&#xff1f; Q2&#xff1a;你看待这次夏令营是认真的吗&#xff1f;还是只是一个演练&…

前缀和(三)

题目&#xff1a;激光炸弹 1 链接 P2280 [HNOI2003] 激光炸弹 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 2.大体思路 先开辟一个全局变量的 s 二维数组&#xff0c;这个二维数组开成 s [ 5010 ] [ 5010 ] &#xff0c;这个是为了&#xff0c;能够将它所给的所有有价值的…

linux命令学习——sort

sort可以对文本文件进行“排序”&#xff0c;比如-n可以对文本&#xff0c;按照首行字母数字顺序排序 -r参数可以对排序结果进行反转 -u参数可以对查看结果去重

React - 面试题

1. React函数式组件和类组件的区别 React 中有两种主要的组件类型&#xff1a;函数式组件和类组件。它们之间的区别主要体现在以下几个方面&#xff1a; 语法&#xff1a; 函数式组件&#xff1a;函数式组件是一个简单的 JavaScript 函数&#xff0c;接收 props 作为参数并返回…

笔记—学习【立创】如何使用示波器—捕捉波形

如何使用示波器的信号触发功能 在工程实践中&#xff0c;经常要测量一些不连续的波形。例如&#xff0c;USART、SPI、IIC通讯&#xff0c;只有在通讯时才会产生相应的波形&#xff0c;如果示波器的触发模式没有选择好的话&#xff0c;我们是看不到这个波形的。 切换触发模式 …

CTK插件框架学习-新建插件(02)

CTK插件框架学习-源码下载编译(01)https://mp.csdn.net/mp_blog/creation/editor/136891825 开发环境 window11、vs17、Qt5.14.0、cmake3.27.4 开发流程 新建ctk框架调用工程&#xff08;CTKPlugin&#xff09; 拷贝CTK源码编译完成后的头文件和库文件到工程目录&#xff0…

Apache Hive的部署与体验

一、Apache Hive概述 什么是分布式SQL计算&#xff1f; 以分布式的形式&#xff0c;执行SQL语句&#xff0c;进行数据统计分析。Apache Hive是做什么的&#xff1f; 很简单&#xff0c;将SQL语句翻译成MapReduce程序&#xff0c;从而提供用户分布式SQL计算的能力。传统MapRed…

尽可能使用清晰、统一的方式初始化所有对象:列表初始化。【C++】

不管是为了统一性&#xff0c;还是避免发生窄化转换&#xff0c;尽可能使用初始化列表。 说明哪些对象可以使用列表初始化&#xff1f;代码演示 说明 C11 引入了列表初始化&#xff08;也称为统一初始化或初始化列表&#xff09;&#xff0c;它是一种使用花括号 {} 来初始化对…

java数据结构与算法刷题-----LeetCode451. 根据字符出现频率排序

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. hash统计出现次数后排序2. 桶排序 1. hash统计出现次数后排序…

一个简单的内存缓存工具

缓存的数据是&#xff1a;List<User> Slf4j public class UserCache {private static volatile List<User> cacheDatas;private static volatile String expireTime;public static void set(List<User> datas, int expireSeconds) {long now DateTimeUtil.…

高性能 MySQL 第四版(GPT 重译)(二)

第四章&#xff1a;操作系统和硬件优化 你的 MySQL 服务器的性能只能和它最弱的环节一样好&#xff0c;而运行 MySQL 的操作系统和硬件通常是限制因素。磁盘大小、可用内存和 CPU 资源、网络以及连接它们的所有组件都限制了系统的最终容量。因此&#xff0c;你需要仔细选择硬件…

LEETCODE-DAY32

title: LEETCODE-DAY32 date: 2024-03-24 13:32:03 tags: 122.买卖股票的最佳时机II、55. 跳跃游戏、45.跳跃游戏II T1 class Solution:def maxProfit(self, prices: List[int]) -> int:result 0for i in range(1, len(prices)):result max(prices[i] - prices[i - 1],…

五款即将登陆Sui的游戏,总有一款适合你

在游戏领域不断演变的道路中&#xff0c;创新是吸引玩家注意力并保持他们参与的关键。展望今年余下的时间&#xff0c;Sui平台上即将推出的五款游戏将展示Web3游戏的可能性。通过运用强大的区块链技术和沉浸式叙事&#xff0c;这些游戏有望为玩家设定新的期望标准。 E4C: Fina…

【C语言】模拟实现 atoi

文章目录 atoi()函数模拟实现思路分析代码呈现 atoi()函数 通过上述cplusplus和MSDN对atoi函数的介绍我们可以得出以下几个关键点 库函数&#xff1a; <stdlib.h>形参&#xff1a;const char * str返回值&#xff1a; int作用&#xff1a;atoi函数是将一个字符串转化成一…

Windows 7 一键恢复 - 联想拯救系统

Windows 7 一键恢复 - 联想拯救系统 1. 联想拯救系统1.1. OEM 分区1.2. 一键恢复 References 1. 联想拯救系统 1.1. OEM 分区 计算机 -> 管理 -> 存储 -> 磁盘管理 1.2. 一键恢复 重新启动电脑 F11 -> 从初始备份恢复 References [1] Yongqiang Cheng, https…

福建科立讯通信 指挥调度管理平台 SQL注入漏洞复现(CVE-2024-2620、CVE-2024-2621)

0x01 产品简介 福建科立讯通信指挥调度管理平台是一个专门针对通信行业的管理平台。该产品旨在提供高效的指挥调度和管理解决方案,以帮助通信运营商或相关机构实现更好的运营效率和服务质量。该平台提供强大的指挥调度功能,可以实时监控和管理通信网络设备、维护人员和工作任…