C++ 四种类型转换
一图速览:C++ 四种类型转换
转换 | 用途 | 检查时机 | 限制 | 风险 |
---|---|---|---|---|
static_cast |
基本转换 / 上行转型 | 编译期 | 不改 const / 无运行时检查 |
中 |
dynamic_cast |
多态下行转型 | 运行期 | 需虚函数;失败返回空/抛异常 | 低 |
const_cast |
改 const /volatile |
编译期 | 真常量不可改 | 视用法 |
reinterpret_cast |
底层重解释 | 编译期 | 不做检查 | 高 |
关键要点
static_cast
:基本类型转换;向上转型安全;不能去掉const/volatile
。dynamic_cast
:需多态,安全下行;失败时指针为nullptr
或抛异常。const_cast
:只改限定符,修改真常量未定义。reinterpret_cast
:位级重解释,风险最高,慎用。
实战建议
- 能不用就不用,避免不必要的转换。
- 首选
static_cast
;向下转型需dynamic_cast
。 - 仅改限定符用
const_cast
。 reinterpret_cast
只在底层需求且明确后果时使用。
相关阅读:关于禁止隐式转换与条件
explicit
的用法与陷阱,见「explicit 关键字的作用」。
代码模式记忆卡
if (auto p = dynamic_cast<Derived*>(base)) {
// use p
}
try {
auto& d = dynamic_cast<Derived&>(base);
} catch (const std::bad_cast&) {
// 失败处理
}
const int* p = /* ... */;
int* q = const_cast<int*>(p); // 去 const(谨慎)
int x = 0;
const int* r = const_cast<const int*>(&x); // 加 const
std::uintptr_t u = reinterpret_cast<std::uintptr_t>(ptr);
auto* p2 = reinterpret_cast<Foo*>(u);
static_cast
基本类型转换
int i = 42;
double d = static_cast<double>(i); // 42 -> 42.0
double pi = 3.14;
int truncated = static_cast<int>(pi); // 结果: 3
static_cast
会遵循既定的转换规则,例如将浮点的小数部分舍弃。
类层次之间的转换
struct Animal {
virtual ~Animal() = default;
};
struct Dog : Animal {
void bark();
};
Dog dog;
Animal* a1 = static_cast<Animal*>(&dog); // 上行转换,安全
Animal* base = &dog;
Dog* d1 = static_cast<Dog*>(base); // 下行转换,需确保 base 的真实对象确实是 Dog
如果
base
实际指向Animal
而非Dog
,使用d1->bark()
会导致未定义行为。若无法保证,考虑dynamic_cast
。
dynamic_cast
指针的安全下行转换
Animal* base = new Dog{};
if (auto* d = dynamic_cast<Dog*>(base)) {
d->bark(); // 转换成功
} else {
// base 不是 Dog*,d 为 nullptr
}
引用的安全下行转换
Animal& ref = dog; // dog 与上文一致
try {
Dog& dref = dynamic_cast<Dog&>(ref);
dref.bark();
} catch (const std::bad_cast&) {
// 转换失败,抛出异常
}
dynamic_cast
依赖多态类型的 RTTI,仅适用于带虚函数的类;若类中没有虚函数,使用dynamic_cast
会在编译期报错。
const_cast
去除常量性
void takes_int(int*);
const int value = 10;
int* writable = const_cast<int*>(&value); // value 是真常量,修改将导致 UB
int n = 20;
takes_int(const_cast<int*>(&n)); // n 可写,可安全修改
添加常量性
void print(const int*);
int x = 5;
print(const_cast<const int*>(&x)); // 将非常量指针视为 const
reinterpret_cast
指针与整数之间
int data = 0x12345678;
std::uintptr_t raw = reinterpret_cast<std::uintptr_t>(&data);
int* p = reinterpret_cast<int*>(raw); // raw 再转回指针
读取对象的字节表示
unsigned char* bytes = reinterpret_cast<unsigned char*>(&data);
for (std::size_t i = 0; i < sizeof(int); ++i) {
std::printf("%02x ", bytes[i]);
}
reinterpret_cast
不改变位模式,只是从新的角度解读内存。使用前务必确认对齐、字节序等问题。