文章目录
- [一、C++ 类型转换的背景](#一、C++ 类型转换的背景)
- [二、C++ 类型转换详解](#二、C++ 类型转换详解)
-
- [▶ static_cast 静态类型转换](#▶ static_cast 静态类型转换)
- [▶ dynamic_cast 动态类型转换](#▶ dynamic_cast 动态类型转换)
- [▶ const_cast 去除或添加 const/volatile](#▶ const_cast 去除或添加 const/volatile)
- [▶ reinterpret_cast 低级重解释转换](#▶ reinterpret_cast 低级重解释转换)
一、C++ 类型转换的背景
在 C 语言中,类型转换通常使用 (type) 的语法进行强制转换(C-style cast),例如:
cpp
int a = 10;
double b = (double)a; // C 风格转换
这种方式虽然简洁,但存在以下问题:
- 安全性差:编译器不会检查转换是否合理;
- 可读性弱:无法从代码中一眼看出转换的意图;
- 维护困难:全局搜索 (int) 会匹配大量无关内容。
为了解决这些问题,C++ 引入了四种更安全、更明确的强制类型转换操作符 ,它们都出现在 C++98 标准 中,并在后续标准(C++11/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),就会读到垃圾内存,甚至程序崩溃! - 样例:
cpp
double d = 3.14;
int i = static_cast<int>(d);
实例
cpp
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {};
};
class Derived : public Base {};
int main() {
// 1. 基本类型转换
double d = 3.14;
int i = static_cast<int>(d); // i = 3
// 2. void* 转换
void* p = &i;
int* ip = static_cast<int*>(p);
// 3. 向上转型(派生类指针->基类指针),安全
Derived d_obj;
Base* b1 = static_cast<Base*>(&d_obj); // OK
// 4. 向下转型(基类指针->派生类指针)危险!无运行时检查
Base* b2 = new Base();
Derived* d_ptr = static_cast<Derived*>(b2); // 编译通过,但运行时行为未定义!
delete b2;
return 0;
}
▶ dynamic_cast 动态类型转换
基本用法
- 作用: 专用于 多态类型之间的安全向下转型(基类->派生类) ,它会在 运行时检查对象的真实类型,故运行时安全! ,若转换失败:
- 对指针:返回
nullptr - 对引用:抛出
std::bad_cast异常
- 对指针:返回
- ⚠️基类必须包含至少一个虚函数,即具有虚表。
- ✅ 应用场景:需要安全地将基类指针/引用转为派生类,且基类是多态的。
- 样例:
cpp
// 1. 安全向下转型,基类指针(本身所指向的就是派生类对象)→派生类指针
Base* b1 = new Derived(); // 基类指针指向派生类对象
Derived* d1 = dynamic_cast<Derived*>(b1); // 转换成功
// 2. 非安全向下转型! 基类指针(本身所指向的就是基类对象)→派生类指针
Base* b2 = new Base();
Derived* d2 = dynamic_cast<Derived*>(b2); // 转换失败,dynamic_cast 返回 nullptr
// 3. 安全向下转型,基类引用(基类引用的是派生类对象)→派生类引用
Derived derived_obj;
Base& ref1 = derived_obj; // 向上转型
Derived& r1 = dynamic_cast<Derived&>(ref1);// 转换成功
// 4. 非安全向下转型! 基类引用(基类引用的是基类对象)→派生类引用
Base base_obj;
Base& ref2 = base_obj;
Derived& r2 = dynamic_cast<Derived&>(ref2); // 转换失败,运行时会抛出 bad_cast!
实例
cpp
#include <iostream>
#include <typeinfo>
using namespace std;
class Base {
public:
virtual ~Base() {} // 必须是多态类型(有虚函数)
};
class Derived : public Base {
public:
void special() {
cout << "Special!\n";
}
};
int main() {
// ========== 指针版本==========
cout << "=== 指针版本 ===" << endl;
Base* b1 = new Derived(); // 基类指针指向派生类对象
Base* b2 = new Base();
// 安全向下转型,基类指针(本身所指向的就是派生类对象)→派生类指针
Derived* d1 = dynamic_cast<Derived*>(b1); // 转换成功
if (d1) {
d1->special();
}
// 非安全向下转型! 基类指针(本身所指向的就是基类对象)→派生类指针
Derived* d2 = dynamic_cast<Derived*>(b2); // 转换失败,dynamic_cast 返回 nullptr
if (!d2) {
cout << "Pointer cast failed!" << endl;
}
delete b1;
delete b2;
// ========== 引用版本==========
cout << "\n=== 引用版本 ===" << endl;
// 1. 安全向下转型,基类引用(基类引用的是派生类对象)→派生类引用
Derived derived_obj;
Base& ref1 = derived_obj; // 向上转型
try {
Derived& r1 = dynamic_cast<Derived&>(ref1); // 转换成功
r1.special(); // 成功调用
} catch (const bad_cast& e) {
cout << "Reference cast failed: " << e.what() << endl;
}
// 2. 非安全向下转型! 基类引用(基类引用的是基类对象)→派生类引用
Base base_obj;
Base& ref2 = base_obj;
try {
Derived& r2 = dynamic_cast<Derived&>(ref2); // 转换失败,运行时会抛出 bad_cast!
r2.special(); // 不会执行到这里
} catch (const bad_cast& e) {
cout << "Reference cast failed: " << e.what() << endl; // 会执行这里
}
return 0;
}

▶ const_cast 去除或添加 const/volatile
基本用法
- 作用: 唯一能修改
const或volatile属性的转换操作符。 常用于:- 去除 const 以调用非 const 成员函数(谨慎!)
- 与 C 接口交互(C 函数参数常为非 const)
- ⚠️const_cast 只能用于
指针、引用或成员指针类型,不能改变对象的实际类型(如int* → double*)。 - ⚠️ 若原对象本身是
const(如字面量、全局 const 变量),去除const后修改会导致 未定义行为(UB)!
实例
cpp
#include <iostream>
using namespace std;
void legacy_func(int* p) { // C 风格函数,参数非 const
*p = 200;
}
int main() {
// const int x = 42;
// int* px = const_cast<int*>(&x); // ❌ 危险!x 是真正的 const
// *px = 99; // UB! 程序可能崩溃
// ✅️ 正确用法:去除指针的const
int y = 50;
const int& cy = y; //引用的 const 性质会传递给它的地址类型: cy 是 const int&,所以 &cy 的类型是 const int*。
int* py = const_cast<int*>(&cy);*py = 100; // 去除 &cy 的const
cout << "y = " << y << endl; // 输出: y = 100
legacy_func(const_cast<int*>(&cy)); // 与 C 接口兼容
cout << "y = " << y << endl; // 输出: y = 200
// ✅️ 正确用法:去除引用的const
int &refy=const_cast<int &>(cy);refy=300; // 去除常引用对象的const
cout << "y = " << y << endl; // 输出: y = 300
return 0;
}

添加 const/volatile(不常用)
- 虽然大家更常听说 const_cast 用于"去掉 const",但 C++ 标准明确允许它双向操作:添加 const 或 volatile。例如:
cpp
int x = 42;
const int* p = const_cast<const int*>(&x); // 添加 const
// 等价于:const int* p = &x; (通常不需要 const_cast)
▶ reinterpret_cast 低级重解释转换
基本用法
- 作用:
直接操作内存中的二进制表示,不进行任何类型安全检查或数据转换。可以转换:任意指针类型之间(包括函数指针、成员指针)指针 ↔ 整数(如int*→char*)不同类型的引用(极危险)
- ❌ 不能转换的类型:基本类型之间 (如
int → double,应使用 static_cast)。
实例
cpp
#include <iostream>
#include <cstdint>
using namespace std;
int main() {
int a = 0x12345678;
int* pa = &a;
// 1. 指针转整数
uintptr_t addr = reinterpret_cast<uintptr_t>(pa);
cout << "Address: 0x" << hex << addr << endl;
// 2. 不同类型指针转换(用于内存查看)
char* pc = reinterpret_cast<char*>(pa); // int* → char*
cout << "First byte: 0x" << (int)(unsigned char)pc[0] << endl;
// 3. 函数指针转换(高级用法,慎用)
void (*func)() = []{ cout << "Lambda called\n"; };
void (*raw_func)() = reinterpret_cast<void(*)()>(func);
raw_func(); // 可能工作,但不保证跨平台
return 0;
}

uintptr_t 系统无符号最大整型
- uintptr_t(u → unsigned 无符号、int → integer 整数、ptr → pointer 指针、_t → type 类型):表示 作用于指针的无符号整数类型,其设计的初衷是 足够的大,能够无损地存储任意指针的值,而且 能够最大存储的数值与系统的寻址能力有关:
| 平台 | 指针大小 | sizeof(uintptr_t) |
典型定义 |
|---|---|---|---|
| 32 位 | 4 字节 | 4 | typedef uint32_t uintptr_t; |
| 64 位 | 8 字节 | 8 | typedef uint64_t uintptr_t; |
- 它定义在头文件
#include <cstdint>(C++11)或#include <stdint.h>(C99)中。