c++的类型转换
在c语言中,类型转换一般是暴力转:
(类型)值 比如 (int)3.14、(char*)ptr这样很明显有一些缺点:
- 什么都能转,没有任何限制指针 ↔ 整数、const ↔ 非 const、无关类型之间乱转 → 极易崩溃、内存越界
- 意图不明确你不知道这是:
- 数值转数值?
- 指针转指针?
- 去掉 const?
- 多态子类转父类?
- 代码里搜不到全是
(...),想排查错误根本找不到 - 编译器无法帮你检查错误
但是c++是强类型语言,在c++中,认为这样很不安全,很乱,所以设置了四个专门用于转换的函数
- 更安全
- 意图更清晰
- 编译器能检查错误
- 代码更容易维护
dynamic_cast<>
动态转化 运行是检查 安全度最高
多态继承安全向下转换要求父类必须存在虚函数
//编译器可能会报错 看编译器,
指针和引用的转换不创建新对象,改变引用/指向
->只适用于上行转化-->子类对象转父类的引用/指针最好
指针失败返回空,引用失败抛出异常
// 指针转换 子类* 指针 = dynamic_cast<子类*>(父类指针); // 引用转换 子类& 引用 = dynamic_cast<子类&>(父类引用); class Father { virtual void func(){} }; // 必须有虚函数 class Son : public Father {}; Father* f = new Son(); // 安全向下转型 Son* s = dynamic_cast<Son*>(f); if(s != nullptr) { // 转换成功 } else { // 转换失败 }✅最佳实践:
- 子类 → 父类(上行):
static_cast/dynamic_cast都安全 - 父类 → 子类(下行):必须用 dynamic_cast
reinterpret_cast
二进制重新解释,不进行任何安全检查,可以进行任意无关类型指针的转换-->针对指针
容易丢数据,编译期
- 指针 ↔ 整数
- 指针 A ↔ 完全无关的指针 B
- 低级硬件操作、地址操作
class a{ }; class b { }; a*a1=new a(); b*b1=new b(); a=reinterpret_cast<a*>(b1); //虽然最后会成功,b的空间会被a指向 但就后面 delete a delete b //就会报错,因为a已经指向b了,delete就delete b,在de b就会错 int a = 10; int* p = &a; // 指针 → 整数 uint64_t addr = reinterpret_cast<uint64_t>(p); // 整数 → 指针 int* q = reinterpret_cast<int*>(addr);- 无关类型指针互转(int↔ char↔ 自定义类指针)
- 指针 和 整型(long/uintptr_t)互相转换
- 底层硬件、网络、二进制数据解析
const_cast
常转换,将const和非const之间进行转化-->(指针和引用类型)
编译期,唯一能修改 const /volatile 属性的转换
// 正确用法 const int a = 10; const int& ar = a; // 常引用 int& a1 = const_cast<int&>(ar); // 移除const → 可修改 a1 = 20; // 合法,但修改原本const变量是未定义行为! // 指针用法 const int* p = &a; int* q = const_cast<int*>(p); // 移除指针的conststatic_cast
静态转换 :编译期完成、仅做语法 / 类型规则检查、无运行时类型校验的显式类型转换
- void*与具体指针类型
- 父子的转换(上行转换安全(子转父),下行不太安全)
- 左值转右值(也可以用c++11的move函数)
- 基础算术类型转换(隐转也可以优先隐)
// 基础类型 double d = 3.14; int i = static_cast<int>(d); // 继承关系 class Father {}; class Son : public Father {}; Son son; Father* f = static_cast<Father*>(&son); // 上行:安全 Son* s = static_cast<Son*>(f); // 下行:不安全! //空指针 void* p = malloc(4); int* q = static_cast<int*>(p);