🧠 C++ 四种类型转换详解
在 C++ 中,为了更安全、更明确地进行类型转换,标准提供了四种命名类型转换操作符。它们分别是:
类型转换 | 用途 |
---|---|
static_cast |
基础类型、向上转型、自定义类型转换 |
dynamic_cast |
多态类的向下转型(运行时检查) |
reinterpret_cast |
强制解释内存布局(底层编程) |
const_cast |
添加/删除 const/volatile 属性 |
🔹 1. static_cast
📌 功能:
用于相关类型之间的转换,如基本数据类型、继承体系中的类指针/引用、支持构造函数或类型转换运算符的自定义类型。
✅ 合法用例:
double d = 3.14;
int i = static_cast<int>(d); // 基本类型转换
class Base {};
class Derived : public Base {};
Derived d_obj;
Base* b = &d_obj; // 向上转型(派生类对象转基类指针)
// 将基类指针转换为派生类指针(向下转型)
Derived* pd = static_cast<Derived*>(b);
⚠️ 注意事项:
- 不进行运行时检查。
- 可以用来调用单参数构造函数或类型转换运算符。
- 不能用于不相关的类型(如
int*
转char*
)。 - 不能去除
const
或volatile
属性。 - 若不确定指针实际指向的类型,应优先使用
dynamic_cast
。
🔹 2. dynamic_cast
📌 功能:
用于多态类型的向下转型(从基类指针/引用转为派生类指针/引用),并在运行时进行类型检查。
✅ 合法用例:
class Base {
public:
virtual void foo() {} // 必须是多态类(有虚函数)
};
class Derived : public Base {};
Base* b = new Derived();
Derived* d = dynamic_cast<Derived*>(b); // 安全的向下转型
if (d) {
// 成功转换
}
⚠️ 注意事项:
- 只适用于多态类型(即含有虚函数的类)。
- 如果转换失败,返回
nullptr
(对指针)或抛出异常(对引用)。 - 比
static_cast
更安全但性能略差。
🔹 3. reinterpret_cast
📌 功能:
最“危险”的转换方式,用于将一种类型强制解释为另一种类型,通常用于底层操作。
✅ 合法用例:
int i = 42;
void* p = &i;
int* pi = reinterpret_cast<int*>(p); // 将 void* 转换为 int*
// 函数指针与不同类型的函数指针互转(非常底层用途)
⚠️ 注意事项:
- 通常用于指针之间的转换。
- 不进行类型安全性检查。
- 可能导致未定义行为。
- 应尽量避免使用,除非你清楚自己在做什么。
🔹 4. const_cast
📌 功能:
用于添加或移除变量的 const
或 volatile
属性。
✅ 合法用例:
const int a = 10;
int* b = const_cast<int*>(&a); // 移除 const 属性
*b = 20; // ❗❗ 未定义行为!因为原始对象是 const
⚠️ 注意事项:
- 只能用于改变
const
和volatile
属性。 - 修改原本声明为
const
的对象内容会导致未定义行为。 - 通常用于适配遗留代码中需要非 const 参数的函数。
🧩 总结对比表
类型转换 | 是否允许 | 是否安全 | 使用场景 |
---|---|---|---|
static_cast |
✅ | ✅ 相对安全 | 基础类型、向上转型、显式构造函数等 |
dynamic_cast |
✅(仅限多态类) | ✅✅ 最安全 | 向下转型、运行时类型检查 |
reinterpret_cast |
✅ | ⚠️ 非常危险 | 底层编程、内存操作 |
const_cast |
✅ | ⚠️ 慎用 | 添加/删除 const/volatile |
📌 推荐使用顺序(按优先级)
- 避免使用类型转换,设计良好的类和接口可以减少转换需求。
- 使用
static_cast
替代传统的(type)
强制转换。 - 在需要运行时检查的向下转型时使用
dynamic_cast
。 - 除非必要,不要使用
reinterpret_cast
和const_cast
。
💡 示例总结
#include <iostream>
using namespace std;
class Base {
public:
virtual void dummy() {}
};
class Derived : public Base {};
int main() {
// static_cast
double d = 3.14;
int i = static_cast<int>(d);
// dynamic_cast
Base* base = new Derived();
Derived* derived = dynamic_cast<Derived*>(base);
// reinterpret_cast
int* ip = new int(5);
void* vp = reinterpret_cast<void*>(ip);
int* ip2 = reinterpret_cast<int*>(vp);
// const_cast
const char* str = "hello";
char* mutable_str = const_cast<char*>(str);
return 0;
}