ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

【C++】C++的类型转换--详解

【C++】C++的类型转换--详解 一.C语言的类型转换在 C 语言里当赋值运算符两边类型不一致、形参和实参类型不匹配、或者函数返回值与接收变量类型不一样时就会触发类型转换。C 语言的类型转换分为两种隐式类型转换与显式类型转换。隐式类型转换由编译器在编译期间自动完成可以转换就执行转换无法转换则直接编译报错。显式类型转换需要程序员手动编写代码完成转换。来看代码#include stdio.h void Test () { int i 1; // 隐式类型转换int自动转为double double d i; printf(%d, %.2f\n , i, d); int* p i; // 显式强制类型转换把指针地址转为整型 //注意指针转int存在平台风险64位下建议用uintptr_t int address (int) p; printf(%p, %d\n , p, address); } int main(void) { Test(); return 0; }C语言强转缺陷转换的可视性较差所有转换都写成同一种形式很难定位出错的类型转换不利于跟踪错误。二.为什么C需要四种类型转换C 风格的转换格式很简单但是有不少缺点的隐式类型转化有些情况下可能会出问题比如数据精度丢失。显式类型转换将所有情况混合在一起代码不够清晰。因此 C 提出了自己的类型转化风格注意因为 C 要兼容 C 语言所以 C 中还可以使用 C 语言的转化风格。三.C 强制类型转换标准 C 为了加强类型转换的可视性引入了四种命名的强制类型转换操作符static_cast普通静态类型转换reinterpret_cast二进制重新解释转换const_cast修改常量属性dynamic_cast多态安全向下转换运行校验1.static_caststatic_cast 适用于非多态类型之间的静态转换。凡是编译器能够自动隐式完成的类型转换都可以使用 static_cast 显式写出但它不支持两个毫无关联的类型相互转换。#include iostream using namespace std; int main() { double d 12.34; // 把double转为int属于相近类型转换static_cast合法 int a static_castint(d); cout a endl; return 0; }double 向 int 转换属于合法的数值类型转换static_cast 在编译阶段完成转换直接舍弃小数部分输出 12。static_cast 不支持无关类型如指针与 int的转换。2.reinterpret_castreinterpret_cast 会直接对数据的二进制位重新解读适合把一种完全不同的类型转换成另一种类型不做类型安全性检查。注意这种转换仅仅改变类型解释方式不会修改内存里的二进制内容风险很高。#include iostream using namespace std; int main() { double d 12.34; int a static_castint(d); cout a endl; // static_cast不支持整型向指针转换编译报错 //int *p static_castint*(a); //强行把整型数值解释成指针地址 int *p reinterpret_castint*(a); return 0; }整型与指针是无关类型static_cast 不支持转换。reinterpret_cast 直接将 a 中的数值解读成指针地址仅改变类型视角不改动二进制数据。该转换语法可行但得到的是无效地址不要对指针解引用风险较大。3.const_castconst_cast 主要用来移除或者增加变量的 const 属性最常见用法是去掉 const 限定。注意它不是真正消除常量本身的只读属性只是修改指针 / 引用的类型如果原本是常量强行修改会出现未定义行为。#include iostream using namespace std; void Test() { const int a 2; //去掉const属性用普通指针接收常量的地址 int* p const_castint*(a); *p 3; cout a endl; } int main() { Test(); return 0; }普通指针无法接收 const 变量的地址借助 const_cast 去除指针的 const 限制。但 a 本身是常量通过指针修改常量属于未定义行为运行结果不确定。const_cast 仅能增减 const 属性不支持其他类型转换。补充实用场景它更适合本来不是常量只是被 const 指针接收的情况这种修改是安全的。如果你想要我可以写一段安全使用 const_cast 的示例。4.dynamic_castdynamic_cast 用来完成父类指针或引用向子类指针或引用的动态转换。向上转型子类指针 / 引用转为父类指针 / 引用依靠赋值兼容规则不需要强制转换。向下转型父类指针 / 引用转为子类指针 / 引用使用 dynamic_cast 可以实现安全转换。注意 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_castB*(pa); B* pb2 dynamic_castB*(pa); cout pb1: pb1 endl; cout pb2: pb2 endl; } int main() { A a; B b; fun(a); fun(b); return 0; }A 类中写了虚函数这是 dynamic_cast 能够正常使用的前提。第一次调用 fun (a)传进去的是父类对象地址。 static_cast 不会在运行时校验对象真实类型直接强制转为 B 类指针拿到的指针是无效的 dynamic_cast 运行时检测出原始对象是父类向下转换行不通直接返回空指针。第二次调用 fun (b)传入子类对象地址。 两种转换都能成功得到子类指针。static_cast 只在编译期间做简单检查向下转型存在安全隐患dynamic_cast 依靠运行时类型判断保证安全多用于多态代码。补充强制类型转换会跳过常规的类型检查。写代码时优先想想有没有不用强制转换的方案。实在不得不使用强制转换尽量缩小它的作用范围减少 bug 出现的可能性。四.RTTI了解RTTIRun-time Type identification 的缩写即运行时类型识别用来在程序运行阶段判断对象的真实类型。C 通过下面几个方式支持 RTTItypeid 运算符返回一个 type_info 对象用来查询表达式的实际类型。dynamic_cast 运算符前面讲过用于多态下安全向下转型能转就转不能转返回空指针。decltype在编译阶段推导表达式的类型主要配合模板和泛型编程使用。补充RTTI 需要依赖虚函数表来记录类型信息所以想要用 RTTI 判断类型前提是类里面包含虚函数通俗理解就是typeid 负责 看是什么类型dynamic_cast 负责 能不能安全转decltype 则偏编译期推导三者应用场景不太一样。
返回列表