个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创C++的类型转换
收录于专栏 [C++进阶学习]
本专栏旨在分享学习C++的一点学习笔记,欢迎大家在评论区交流讨论💌
目录
1. C语言中的类型转换
在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与
接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型
转换和显式类型转换。
1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
2. 显式类型转化:需要用户自己处理
#include <stdio.h>
void Test()
{
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);
}
int main()
{
Test();
return 0;
}
缺陷:
转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换
2. C++四种强制类型转换
2.1 static_cast
static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换
int main()
{
double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl;
return 0;
}
2.2 reinterpret_cast
reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换
为另一种不同的类型
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;
}
2.3 const_cast
const_cast最常用的用途就是删除变量的const属性,方便赋值
#include <stdio.h>
#include <iostream>
using namespace std;
void Test()
{
const int a = 2;
int* p = const_cast<int*>(&a);
*p = 3;
cout << a << endl;
}
int main()
{
Test();
return 0;
}
2.4 dynamic_cast
dynamic_cast用于将一个父类对象的指针 / 引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针 / 引用->父类指针 / 引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针 / 引用->子类指针 / 引用(用dynamic_cast转型是安全的)
注意:
1. dynamic_cast只能用于父类含有虚函数的类
2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
#include <iostream>
using namespace std;
class A
{
public:
virtual void f() {}
};
class B : public A
{};
void fun(A* pa)
{
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
if (pb1 == nullptr) {
cout << "pb1 is nullptr (static_cast) - potential unsafe cast!" << endl;
}
else {
cout << "pb1 (static_cast): " << pb1 << endl;
}
if (pb2 == nullptr) {
cout << "pb2 is nullptr (dynamic_cast) - cast failed!" << endl;
}
else {
cout << "pb2 (dynamic_cast): " << pb2 << endl;
}
}
int main()
{
A a; // A 类型的对象
B b; // B 类型的对象
fun(&a); // 传递 A 类型的对象
fun(&b); // 传递 B 类型的对象
return 0;
}
注意
强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会。强烈建议:避免使用强制类型转换
3. 为什么C++需要四种类型转换
C风格的转换格式很简单,但是有不少缺点的:
1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
2. 显式类型转换将所有情况混合在一起,代码不够清晰
因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的
转化风格。
4. RTTI
RTTI(Runtime Type Identification,运行时类型识别)是 C++ 中的一种机制,允许在运行时确定对象的动态类型。它主要通过 typeid 运算符和 dynamic_cast
typeid 操作符:
返回一个表示类型信息的 type_info 对象,可以通过它获取对象的类型名称等信息。
#include <iostream>
#include <typeinfo>
class A {};
class B : public A {};
int main() {
A a;
B b;
std::cout << typeid(a).name() << std::endl; // 输出 A 的类型名
std::cout << typeid(b).name() << std::endl; // 输出 B 的类型名
A* pa = &b;
std::cout << typeid(*pa).name() << std::endl; // 输出 B 的类型名
return 0;
}
dynamic_cast 操作符:
用于安全地进行类型转换,特别是在多态类的情况下。dynamic_cast 能够检查转换是否有效,如果转换失败,则返回 nullptr(对于指针)或抛出 std::bad_cast 异常(对于引用)。
B* pb = dynamic_cast<B*>(pa); // 如果 pa 指向 B 的实例,pb 将有效;否则,pb 为 nullptr。
RTTI 是 C++ 中的重要特性,允许程序在运行时进行类型识别和安全的类型转换。这对于使用多态的面向对象编程模式尤为重要,有助于编写更安全和灵活的代码。
5. C++类型转换总结
在 C++ 中,有四种主要的类型转换方式,它们分别是:
隐式转换(Implicit Conversion)
显式转换(Explicit Conversion),通常使用类型转换运算符。
static_cast
dynamic_cast
const_cast
reinterpret_cast
各个转换的应用场景:
1. 隐式转换(Implicit Conversion)
应用场景:在需要自动进行类型转换的情况下,例如将 int 类型赋值给 float 类型时,编译器会自动进行转换。这种转换可以减少代码的复杂性。
2. 显式转换(Explicit Conversion)
应用场景:当你想要控制类型转换的行为时,可以使用显式转换。特别是在将不同类型的数据进行混合计算时,确保转换是安全的。
3. static_cast
应用场景:在进行较为简单的转换时,比如基类指针到派生类指针的转换(在编译时已知对象类型)或基本数据类型之间的转换。static_cast 不会执行运行时检查。
4. dynamic_cast
应用场景:在涉及多态的情况下,当你需要安全地将基类指针转换为派生类指针时使用,尤其是当你不确定对象的实际类型时。dynamic_cast 在运行时检查类型安全。
5. const_cast
应用场景:用于修改对象的常量性,例如从一个 const 对象获取非 const 指针。常用于需要改变某个函数参数的常量性时。
6. reinterpret_cast
应用场景:进行低级别的类型转换,例如将指针类型转换为其他不相关类型的指针。通常用于与硬件或内存映射等底层操作时。