C++显式类型转换

2024-05-16 06:20
文章标签 c++ 类型转换 显式

本文主要是介绍C++显式类型转换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文主要分析C++的4种显式类型转换

文章目录

  • static_cast
    • 基本数据类型转换
    • const
    • 用于类层次结构
    • void*
  • dynamic_cast
    • 继承中的转换
  • const_cast
  • reinterpret_cast
  • 参考资料


我们使用显示类型转换,就是在告诉编译器要怎么解释这块内存。

在早期C/C++中,显式的类型转换有如下两种形式

type(expr); // 函数形式的显式类型转换
(type)expr; // C语言风格 

C++的新式显式类型转换

cast-name<type>(expression);
  • cast-namestatic_castdynamic_castconst_castreinterpret_cast 四种,表示转换的方式
  • type表示转换的目标类型
  • expression 是被转换的值

下面详细讲解下这四种显式类型转换


static_cast

格式为 static_cast<type>(expression)

任何在编写程序时能够明确的类型转换都可以使用 static_cast

基本数据类型转换

基本数据类型转换,比如将int转换为double,反之亦然,需要编写程序时确认安全性

将 `int` 转换为 `double` 编译器可能的操作如下(VS2022 x64),比如有如下代码
int x = 0;
double y = static_cast<double>(x);

其汇编码为,cvtsi2sd 指令把源地址1个双字有符号整数变成1个双精度浮点数,xmm0 为英特尔处理器中的一个128位寄存器,movsd mmword ptr [y],xmm0 指令表示从 xmm0 寄存器中移动低64位到 y 地址

const

将非const对象转换为const对象 (但不能将const对象转换为非const对象,这个只有const_cast才能做到)
如果转换底层 const 对象到非 const 对象,编译器会报表达式必须是可修改的左值错误

顶层 const 也不可以被 static_cast 转换

用于类层次结构

父类和子类之间指针和引用的转换
假设我们现在有两个类,父类 A 和其派生类 B

class A {
public:virtual void foo() {std::cout << "A::foo()" << std::endl;}int m_a = 0;
};class B : public A
{
public:virtual void foo() {std::cout << "B::foo()" << std::endl;}int m_b = 0;
};
  • 进行上行转换,即把子类对象的指针/引用转换为父类指针/引用,这种转换是安全的
B b;
static_cast<A>(b).foo();
B* bptr = new B;
static_cast<A*>(bptr)->foo();

输出如下

  • 进行下行转换,即把父类对象的指针/引用转换成子类指针/引用,这种转换是不安全的,因为没有运行时检查,所以需要在编写程序时确认安全性
A* a = new A;
std::cout << static_cast<B*>(a)->m_b << std::endl; // 不安全的,访问了申请外的内存

输出如下

void*

void* 转换为目标类型的指针(这是极其不安全的),类似于上面父类指针转子类指针,可能会访问申请外的内存

void* a = new A;
std::cout << static_cast<B*>(a)->m_b << std::endl; // 不安全的,访问了申请外的内存

输出如下


dynamic_cast

格式为 dynamic_cast<type>(expression)

相比static_castdynamic_cast 会在运行时检查类型转换是否合法,具有一定的安全性。由于运行时的检查,所以会额外消耗一些性能。需要注意的是 dynamic_cast 转换仅适用于指针或引用

继承中的转换

  1. 上行转换

由子类指针/引用转换到父类指针/引用,与 static_cast 和隐式转换一样,都是安全的

B* b = new B;
A* a = dynamic_cast<A*>(b);
std::cout << a->m_a << std::endl;

可以看到下面的汇编代码中,只是把指针的值给到了 [a] 地址

  1. 下行转换

由父类指针/引用转换到子类指针/引用,使用 dynamic_cast 进行下行转换有个条件,就是其操作数必须含有多态类类型,简单理解,父类得有虚函数。

如果我们将之前 类A 和 类B 中的虚函数去掉,则会报错

如果和之前一样,类 A 中有虚函数 foo(),那么执行 dynamic_cast 会发生什么

A* a = new A;
B* b = dynamic_cast<B*>(a);
std::cout << b->m_b << std::endl;

可以看到把类 B 和类 A 的运行时类型描述符放到了 r9r8 寄存器中

之后运行时动态类型转换,这里的实现原理简单描述为,我们在虚函数表 vtbl[-1] 的位置存放着指向类型信息的 tpye_info*,那么由于我们实际指向的对象的类是 A 其取出的 RTTI Type Descriptor 应该是类 A 我们和需要转换的类 B 的 RTTI Type Descriptor 比较,然后发现不匹配,此时转换失败,会返回一个 nullptr。

如果 a 实际指向的是类 B 的对象,那么运行时转换成功。

注意转换的是引用,转换失败会抛出 bad_cast 异常


const_cast

格式为 const_cast<type>(expression)

const_cast 用于移除类型的 constvolatile_unaligned 属性

const A* const a = new A;
A* aa = const_cast<A*>(a);
aa->m_a = 2;

当然也可以用于添加 const


reinterpret_cast

格式为 reinterpret_cast<type>(expression)

非常激进的指针类型转换,在编译期完成,可以转换任何类型的指针,所以极不安全。非极端情况不要使用


参考资料

C++笔记 · C++类型转换 —— 默默默默默
C++对象模型之RTTI的实现原理 —— linux

这篇关于C++显式类型转换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/994118

相关文章

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

python中的显式声明类型参数使用方式

《python中的显式声明类型参数使用方式》文章探讨了Python3.10+版本中类型注解的使用,指出FastAPI官方示例强调显式声明参数类型,通过|操作符替代Union/Optional,可提升代... 目录背景python函数显式声明的类型汇总基本类型集合类型Optional and Union(py

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

C++归并排序代码实现示例代码

《C++归并排序代码实现示例代码》归并排序将待排序数组分成两个子数组,分别对这两个子数组进行排序,然后将排序好的子数组合并,得到排序后的数组,:本文主要介绍C++归并排序代码实现的相关资料,需要的... 目录1 算法核心思想2 代码实现3 算法时间复杂度1 算法核心思想归并排序是一种高效的排序方式,需要用

Oracle迁移PostgreSQL隐式类型转换配置指南

《Oracle迁移PostgreSQL隐式类型转换配置指南》Oracle迁移PostgreSQL时因类型差异易引发错误,需通过显式/隐式类型转换、转换关系管理及冲突处理解决,并配合验证测试确保数据一致... 目录一、问题背景二、解决方案1. 显式类型转换2. 隐式转换配置三、维护操作1. 转换关系管理2.

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3