当前位置: 首页 > backend >正文

【重走C++学习之路】26、类型转换

目录

一、C语言中的类型转换

二、C++中的四个类型转换

2.1 static_cast

2.2 dynamic_cast 

2.3 const_cast 

2.4  reinterpret_cast

2.5 总结 

结语


一、C语言中的类型转换

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

隐式类型转换(截断或提升):

编译器在编译阶段自动进行,能转就转,不能转就编译失败

double pi = 3.14159;
int truncatedPi = pi;  // 隐式转换,丢失小数部分
printf("Pi: %d\n", truncatedPi);  // 输出:3
return 0;

隐式转换可能导致数据丢失:在隐式类型转换中,可能会将一个较大范围的数据类型转换为一个较小范围的类型,导致数据丢失或精度损失。例如,double 转换为 int,会丢失小数部分。 

显式类型转换(强转)

用户自己手动强制转换变量类型

int num = 100;
int *int_ptr = #
void *void_ptr = (void*)int_ptr;  // 将int指针转换为void指针
int *new_int_ptr = (int*)void_ptr;  // 再将void指针转换回int指针

常见场景:

  • 数值类型转换
  • 指针类型转换
  • 函数参数类型适配

注意:

  • 数据截断风险
    在把大范围的数据类型转换为小范围的数据类型(例如从long转换为int)时,可能会导致数据截断。
  • 浮点精度丢失
    double类型转换为float类型时,可能会造成精度的损失。
  • 指针转换的危险性
    错误的指针类型转换可能会使程序崩溃或者产生未定义行为。

二、C++中的四个类型转换

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

1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失

2. 显式类型转换将所有情况混合在一起,代码不够清晰

因此C++提出了自己的类型转换风格,但C++中仍然可以使用C的类型转换。

在 C++ 里,为了进行类型转换,提供了四个功能不同的类型转换运算符,分别是static_castdynamic_castconst_cast以及reinterpret_cast

2.1 static_cast

static_cast主要用于进行良性转换,非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换。它在编译阶段就会完成类型检查

使用格式:

static_cast<new_type>(expression)

使用场景:

  • 基本数据类型之间的转换
double d = 3.14;
int i = static_cast<int>(d);  // 把double类型转换为int类型,值为3
  • 子类到父类的向上转型
class Base {};
class Derived : public Base {};Derived d;
Base* b = static_cast<Base*>(&d);  // 安全的向上转型
  • 显式调用转换构造函数或者转换运算符
class Fraction 
{
public:Fraction(int num, int den = 1) : numerator(num), denominator(den) {}operator double() const { return (double)numerator / denominator; }
private:int numerator;int denominator;
};Fraction f(3, 4);
double d = static_cast<double>(f);  // 调用operator double()

2.2 dynamic_cast 

dynamic_cast主要用于进行安全的向下转型(将父类指针或引用转换为子类指针或引用),它会在运行时进行类型检查。如果转换不安全,对于指针会返回nullptr,对于引用则会抛出std::bad_cast异常。

使用格式:

dynamic_cast<new_type>(expression)

使用场景:

  • 安全的向下转型
class Base { virtual void dummy() {} };  // 必须有虚函数,才能进行RTTI
class Derived : public Base {};Base* b = new Derived;
Derived* d = dynamic_cast<Derived*>(b);  // 转换成功,d不为nullptr
  • 交叉转型 
class Base { virtual void dummy() {} };
class Derived1 : public Base {};
class Derived2 : public Base {};
class Derived3 : public Derived1, public Derived2 {};Derived3* d3 = new Derived3;
Derived1* d1 = dynamic_cast<Derived1*>(d3);  // 转换成功
Derived2* d2 = dynamic_cast<Derived2*>(d1);  // 交叉转型,d2不为nullptr

2.3 const_cast 

const_cast专门用于修改类型的constvolatile属性,主要用于去除const限定(但要注意,通过这种方式修改原本为const的对象是未定义行为)。

使用格式:

const_cast<new_type>(expression)

使用场景:

  • 去除函数参数的const属性
void print(char* str) 
{printf("%s\n", str);
}const char* cstr = "Hello";
char* str = const_cast<char*>(cstr);  // 去除const限定
// print(cstr);  // 错误:不能将const char*传递给char*
print(str);     // 正确
  • const成员函数中修改对象状态
class Counter 
{
public:void increment() const {// count++;  // 错误:在const成员函数中不能修改成员变量const_cast<int&>(count)++;  // 正确:去除const限定}
private:int count;
};

2.4  reinterpret_cast

reinterpret_cast用于进行低级的类型重新解释,比如将指针转换为整数,或者将一种类型的指针转换为另一种不相关类型的指针。

使用格式:

reinterpret_cast<new_type>(expression)

使用场景:

  • 指针和整数之间的转换 
int* ptr = new int(10);
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);  // 将指针转换为整数
int* new_ptr = reinterpret_cast<int*>(addr);  // 将整数转换回指针
  • 不相关类型指针之间的转换
int num = 10;
int* int_ptr = &num;
char* char_ptr = reinterpret_cast<char*>(int_ptr);  // 将int指针转换为char指针
  • 函数指针类型的转换
typedef void (*FuncPtr)();int add(int a, int b) 
{ return a + b; 
}FuncPtr func = reinterpret_cast<FuncPtr>(add);  // 函数指针类型转换
// func();  // 调用会导致未定义行为

2.5 总结 

转换运算符主要用途安全性
static_cast基本类型转换、向上 / 向下转型(不进行运行时检查)中等
dynamic_cast安全的向下转型、交叉转型(运行时类型检查)
const_cast修改const/volatile属性低(容易导致未定义行为)
reinterpret_cast低级指针类型重新解释、指针与整数转换极低(非常危险)

结语

在实际编程中,优先使用C++风格的类型转换,避免使用C风格的强制类型转换,提高代码的安全性和可读性,这种用法会在Linux编程中见到。

下一篇将会介绍C++中IO流相关的知识,可以看作文件操作,有兴趣的朋友可以关注一下。

http://www.xdnf.cn/news/3563.html

相关文章:

  • Python爬虫基础总结
  • [android]MT6835 Android 关闭selinux方法
  • 【自然语言处理与大模型】使用Xtuner进行QLoRA微调实操
  • 【中间件】brpc_基础_bthread头文件
  • 【AI面试准备】Git与CI/CD及单元测试实战指南
  • 从 “零” 做个开源音乐软件“SteadyBeat”吧!<1> 准备
  • NVIDIA NPP 库入门
  • c++_csp-j算法 (6)_高精度算法(加减乘除)
  • PostgreSQL:pgJDBC 下载和安装
  • TensorZero开源程序创建了一个反馈循环来优化 LLM 应用程序,将生产数据转化为更智能、更快、更便宜的模型
  • Leetcode刷题记录26——轮转数组
  • 数字时代,如何为个人信息与隐私筑牢安全防线?
  • Laravel Octane 项目加速与静态资源优化指南
  • MySQL基本查询(二)
  • QT6(32)4.5常用按钮组件:Button 例题的代码实现
  • 【python】【UV】一篇文章学完新一代 Python 环境与包管理器使用指南
  • 手机的数据楚门世界是如何推送的
  • word交叉引用图片、表格——只引用编号的处理方法
  • 4.27-5.4学习周报
  • 【KWDB 创作者计划】技术解读:多模架构、高效时序数据处理与分布式实现
  • ubuntu的libc 库被我 sudo apt-get --reinstall install libc6搞没了
  • WPF之ProgressBar控件详解
  • 学习:困?
  • Nginx部署Vue+ElementPlus应用案例(基于腾讯云)
  • 基于Redis实现-UV统计
  • Linux:系统延迟任务及定时任务
  • 柔性PZT压电薄膜多维力传感器在微创手术机器人的应用
  • [英语单词] from under
  • 【STM32】定时器
  • React memo