【C++类型转换】static_cast、dynamic_cast、const_cast、reinterpret_cast
文章目录一、C 类型转换的背景二、C 类型转换详解▶ static_cast 静态类型转换基本用法实例▶ dynamic_cast 动态类型转换基本用法实例▶ const_cast 去除或添加 const/volatile基本用法实例添加 const/volatile不常用▶ reinterpret_cast 低级重解释转换基本用法实例uintptr_t 系统无符号最大整型一、C 类型转换的背景在 C 语言中类型转换通常使用(type)的语法进行强制转换C-style cast例如inta10;doubleb(double)a;// C 风格转换这种方式虽然简洁但存在以下问题安全性差编译器不会检查转换是否合理可读性弱无法从代码中一眼看出转换的意图维护困难全局搜索 (int) 会匹配大量无关内容。为了解决这些问题C 引入了四种更安全、更明确的强制类型转换操作符它们都出现在C98 标准中并在后续标准C11/14/17/20中保持稳定。这四种转换分别是static_cast、、dynamic_cast、const_cast、reinterpret_cast。这四大类型是 C 对 C 风格强制转换的现代化、安全化替代方案。二、C 类型转换详解▶ static_cast 静态类型转换基本用法作用用于编译期可确定的、相对安全的类型转换包括基本类型之间的转换如int↔double。指针/引用在有继承关系的类之间 向上或向下转换但不安全。void*与其他指针类型之间的转换。显式调用构造函数或转换函数如 const char* →std::string可直接将 char * 、const char * 类型的对象赋值给 string 对象enum 与整型之间。void*与其他指针类型之间但不能用于函数指针。⚠️注意static_cast 不进行运行时类型检查向下转型基类 → 派生类可能不安全比如内存里实际只分配了 Base 基类 的大小比如 8 字节但 Derived 派生类可能更大比如 16 字节因为它有额外成员现在你拿着一个 Derived* 指针以为它后面有 16 字节数据其实只有 8 字节是合法的。如果你访问 Derived 特有的成员比如 d_ptr-extraData就会读到垃圾内存甚至程序崩溃样例doubled3.14;intistatic_castint(d);实例#includeiostreamusingnamespacestd;classBase{public:virtual~Base(){};};classDerived:publicBase{};intmain(){// 1. 基本类型转换doubled3.14;intistatic_castint(d);// i 3// 2. void* 转换void*pi;int*ipstatic_castint*(p);// 3. 向上转型派生类指针-基类指针安全Derived d_obj;Base*b1static_castBase*(d_obj);// OK// 4. 向下转型基类指针-派生类指针危险无运行时检查Base*b2newBase();Derived*d_ptrstatic_castDerived*(b2);// 编译通过但运行时行为未定义deleteb2;return0;}▶ dynamic_cast 动态类型转换基本用法作用专用于多态类型之间的安全向下转型基类-派生类它会在运行时检查对象的真实类型故运行时安全若转换失败对指针返回nullptr对引用抛出std::bad_cast异常⚠️基类必须包含至少一个虚函数即具有虚表。✅应用场景需要安全地将基类指针/引用转为派生类且基类是多态的。样例// 1. 安全向下转型基类指针(本身所指向的就是派生类对象)→派生类指针Base*b1newDerived();// 基类指针指向派生类对象Derived*d1dynamic_castDerived*(b1);// 转换成功// 2. 非安全向下转型! 基类指针(本身所指向的就是基类对象)→派生类指针Base*b2newBase();Derived*d2dynamic_castDerived*(b2);// 转换失败dynamic_cast 返回 nullptr// 3. 安全向下转型基类引用(基类引用的是派生类对象)→派生类引用Derived derived_obj;Baseref1derived_obj;// 向上转型Derivedr1dynamic_castDerived(ref1);// 转换成功// 4. 非安全向下转型! 基类引用(基类引用的是基类对象)→派生类引用Base base_obj;Baseref2base_obj;Derivedr2dynamic_castDerived(ref2);// 转换失败运行时会抛出 bad_cast实例#includeiostream#includetypeinfousingnamespacestd;classBase{public:virtual~Base(){}// 必须是多态类型有虚函数};classDerived:publicBase{public:voidspecial(){coutSpecial!\n;}};intmain(){// 指针版本cout 指针版本 endl;Base*b1newDerived();// 基类指针指向派生类对象Base*b2newBase();// 安全向下转型基类指针(本身所指向的就是派生类对象)→派生类指针Derived*d1dynamic_castDerived*(b1);// 转换成功if(d1){d1-special();}// 非安全向下转型! 基类指针(本身所指向的就是基类对象)→派生类指针Derived*d2dynamic_castDerived*(b2);// 转换失败dynamic_cast 返回 nullptrif(!d2){coutPointer cast failed!endl;}deleteb1;deleteb2;// 引用版本cout\n 引用版本 endl;// 1. 安全向下转型基类引用(基类引用的是派生类对象)→派生类引用Derived derived_obj;Baseref1derived_obj;// 向上转型try{Derivedr1dynamic_castDerived(ref1);// 转换成功r1.special();// 成功调用}catch(constbad_caste){coutReference cast failed: e.what()endl;}// 2. 非安全向下转型! 基类引用(基类引用的是基类对象)→派生类引用Base base_obj;Baseref2base_obj;try{Derivedr2dynamic_castDerived(ref2);// 转换失败运行时会抛出 bad_castr2.special();// 不会执行到这里}catch(constbad_caste){coutReference cast failed: e.what()endl;// 会执行这里}return0;}▶ const_cast 去除或添加 const/volatile基本用法作用唯一能修改const或volatile属性的转换操作符。常用于去除 const 以调用非 const 成员函数谨慎与 C 接口交互C 函数参数常为非 const⚠️const_cast 只能用于指针、引用或成员指针类型不能改变对象的实际类型如int* → double*。⚠️若原对象本身是const如字面量、全局 const 变量去除const后修改会导致 未定义行为UB实例#includeiostreamusingnamespacestd;voidlegacy_func(int*p){// C 风格函数参数非 const*p200;}intmain(){// const int x 42;// int* px const_castint*(x); // ❌ 危险x 是真正的 const// *px 99; // UB! 程序可能崩溃// ✅️ 正确用法去除指针的constinty50;constintcyy;//引用的 const 性质会传递给它的地址类型: cy 是 const int所以 cy 的类型是 const int*。int*pyconst_castint*(cy);*py100;// 去除 cy 的constcouty yendl;// 输出: y 100legacy_func(const_castint*(cy));// 与 C 接口兼容couty yendl;// 输出: y 200// ✅️ 正确用法去除引用的constintrefyconst_castint(cy);refy300;// 去除常引用对象的constcouty yendl;// 输出: y 300return0;}添加 const/volatile不常用虽然大家更常听说 const_cast 用于“去掉 const”但 C 标准明确允许它双向操作添加 const 或 volatile。例如intx42;constint*pconst_castconstint*(x);// 添加 const// 等价于const int* p x; 通常不需要 const_cast▶ reinterpret_cast 低级重解释转换基本用法作用直接操作内存中的二进制表示不进行任何类型安全检查或数据转换。可以转换任意指针类型之间包括函数指针、成员指针指针 ↔ 整数如int*→char*不同类型的引用极危险❌不能转换的类型基本类型之间如int → double应使用 static_cast。实例#includeiostream#includecstdintusingnamespacestd;intmain(){inta0x12345678;int*paa;// 1. 指针转整数uintptr_t addrreinterpret_castuintptr_t(pa);coutAddress: 0xhexaddrendl;// 2. 不同类型指针转换用于内存查看char*pcreinterpret_castchar*(pa);// int* → char*coutFirst byte: 0x(int)(unsignedchar)pc[0]endl;// 3. 函数指针转换高级用法慎用void(*func)()[]{coutLambda called\n;};void(*raw_func)()reinterpret_castvoid(*)()(func);raw_func();// 可能工作但不保证跨平台return0;}uintptr_t 系统无符号最大整型uintptr_tu → unsigned 无符号、int → integer 整数、ptr → pointer 指针、_t → type 类型表示 作用于指针的无符号整数类型其设计的初衷是足够的大能够无损地存储任意指针的值而且能够最大存储的数值与系统的寻址能力有关平台指针大小sizeof(uintptr_t)典型定义32 位4 字节4typedef uint32_t uintptr_t;64 位8 字节8typedef uint64_t uintptr_t;它定义在头文件#include cstdintC11或#include stdint.hC99中。