在 C++ 中,提供了四种主要的类型转换操作符(cast),它们统称为 _cast 函数,用于在不同类型之间进行显式类型转换。这些操作符分别是 static_cast、dynamic_cast、const_cast 和 reinterpret_cast。它们取代了 C 风格的强制类型转换(如 (type)expression),提供了更安全、更清晰的类型转换方式。以下是对这四个 _cast 函数的详细讲解,包括它们的用途、语法、特点以及使用场景。
static_cast
定义
static_cast 是一种在编译时进行类型转换的操作符,用于执行相对安全的类型转换。它不会进行运行时类型检查,因此效率较高,但需要程序员确保转换的正确性。
语法
用途
- 基本数据类型转换:在内置类型之间进行转换,例如
int 到 float、指针类型之间的转换(在安全的情况下)。 - 类层次结构中的向上转换:将派生类指针或引用转换为基类指针或引用(这是安全的,因为派生类对象总是包含基类部分)。
- 调用显式构造函数或转换函数:用于调用用户定义的类型转换(例如通过构造函数或转换运算符)。
- 枚举类型与整数类型之间的转换。
特点
- 编译时检查:
static_cast 在编译时完成类型转换,不涉及运行时开销。 - 安全性:适用于明确知道类型关系的场景。程序员需要确保转换是合法的,否则可能导致未定义行为。
- 不支持不相关类型之间的转换:不能直接将不相关的指针类型(如
int* 到 double*)转换。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <iostream> using namespace std;
class Base {}; class Derived : public Base {};
int main() { int i = 10; double d = static_cast<double>(i); cout << "d = " << d << endl;
Derived derived; Base* base_ptr = static_cast<Base*>(&derived);
struct MyType { operator int() { return 42; } }; MyType mt; int val = static_cast<int>(mt); cout << "val = " << val << endl;
return 0; }
|
注意事项
static_cast 不能去除 const 属性(需要用 const_cast)。- 不支持运行时类型检查,因此不能用于多态类型之间的向下转换(派生类到基类的转换需要
dynamic_cast)。
dynamic_cast
定义
dynamic_cast 用于在类层次结构中进行安全的类型转换,主要用于多态类型的指针或引用转换。它在运行时进行类型检查,依赖于运行时类型信息(RTTI,Run-Time Type Information)。
语法
用途
- 多态类型之间的向下转换:将基类指针或引用转换为派生类指针或引用,检查对象是否确实是目标类型。
- 运行时类型检查:确保转换的安全性,如果转换失败,返回
nullptr(对于指针)或抛出 bad_cast 异常(对于引用)。
特点
- 运行时检查:依赖 RTTI,需要类具有虚函数(多态性)。
- 安全性:如果转换不合法,
dynamic_cast 会返回 nullptr(指针)或抛出异常(引用)。 - 性能开销:由于运行时检查,
dynamic_cast 比 static_cast 慢。 - 限制:只适用于具有虚函数的类(多态类型),否则编译失败。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <iostream> using namespace std;
class Base { public: virtual ~Base() {} };
class Derived : public Base {};
int main() { Base* base = new Derived;
Derived* derived = dynamic_cast<Derived*>(base); if (derived) { cout << "Conversion succeeded" << endl; } else { cout << "Conversion failed" << endl; }
Base* base2 = new Base; Derived* derived2 = dynamic_cast<Derived*>(base2); if (derived2) { cout << "Conversion succeeded" << endl; } else { cout << "Conversion failed" << endl; }
Base& base_ref = *base; try { Derived& derived_ref = dynamic_cast<Derived&>(base_ref); cout << "Reference conversion succeeded" << endl; } catch (const bad_cast& e) { cout << "Reference conversion failed: " << e.what() << endl; }
delete base; delete base2; return 0; }
|
注意事项
- 确保类层次结构中至少有一个虚函数,否则
dynamic_cast 会导致编译错误。 - 使用
dynamic_cast 时,通常需要检查返回的指针是否为 nullptr 或捕获引用转换的异常。 - 如果不需要运行时检查,优先使用
static_cast 以提高性能。
const_cast
定义
const_cast 用于添加或移除变量的 const 或 volatile 限定符。它的主要作用是修改类型的常量性或易变性。
语法
用途
- 移除
const 或 volatile 属性:允许修改原本被声明为 const 的对象(但前提是对象本身不是真正的 const)。 - 与
const 不匹配的函数调用:用于传递参数给不接受 const 参数的函数。
特点
- 仅影响
const 或 volatile 限定符:不会更改底层类型(如将 int* 转为 double*)。 - 潜在危险:如果对真正的
const 对象进行修改,会导致未定义行为。 - 典型场景:用于调用遗留代码中不接受
const 参数的函数。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <iostream> using namespace std;
void modify(int* ptr) { *ptr = 100; }
int main() { const int val = 10; int* ptr = const_cast<int*>(&val);
int x = 20; const int* const_ptr = &x; int* mutable_ptr = const_cast<int*>(const_ptr); *mutable_ptr = 30; cout << "x = " << x << endl;
modify(const_cast<int*>(const_ptr)); cout << "x = " << x << endl;
return 0; }
|
注意事项
- 未定义行为:对真正的
const 对象(如 const int val)进行修改会导致未定义行为。 - 谨慎使用:仅在明确知道对象非
const 或需要与旧代码接口兼容时使用。 const_cast 通常用于指针或引用,不能用于基本类型的直接转换。
reinterpret_cast
定义
reinterpret_cast 是最不安全的类型转换操作符,用于在不相关类型之间进行低级别的重新解释。它不检查类型安全性,完全依赖程序员的判断。
语法
1
| reinterpret_cast<目标类型>(表达式)
|
用途
- 指针类型之间的转换:将一种类型的指针转换为另一种类型的指针(如
int* 到 char*)。 - 指针与整数之间的转换:将指针转换为整数类型(如
uintptr_t)或反之。 - 处理硬件相关代码:常用于嵌入式系统或与硬件交互的场景。
- 函数指针转换:将一种函数指针类型转换为另一种函数指针类型。
特点
- 不安全:
reinterpret_cast 不保证转换后指针的有效性,结果可能不可移植或导致未定义行为。 - 底层操作:直接重新解释二进制位模式,不进行任何类型检查。
- 跨平台差异:转换结果可能依赖于平台(如指针大小、字节序)。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <iostream> #include <cstdint> #include <new> using namespace std;
int main() { int x = 42; int* int_ptr = &x; char* char_ptr = reinterpret_cast<char*>(int_ptr); cout << "char_ptr points to: " << static_cast<void*>(char_ptr) << endl;
uintptr_t int_val = reinterpret_cast<uintptr_t>(int_ptr); cout << "int_ptr as integer: " << int_val << endl;
void (*func_ptr)() = [](){ cout << "Hello" << endl; }; using NewFuncType = void(*)(); NewFuncType new_func = reinterpret_cast<NewFuncType>(func_ptr); new_func();
alignas(alignof(long)) unsigned char buf[sizeof(long)]; long* pLong = new (buf) long{123456789L}; unsigned char* bytes = reinterpret_cast<unsigned char*>(pLong); cout << "first byte = " << static_cast<int>(bytes[0]) << endl; return 0; }
|
注意事项
- 未定义行为风险:错误使用
reinterpret_cast 可能导致程序崩溃或不可预测的结果。 - 平台依赖性:转换结果可能在不同平台上表现不同,需谨慎使用。
- 尽量避免:除非在低级别编程(如驱动开发、嵌入式系统)中,否则应尽量避免使用
reinterpret_cast。
std::any 与 std::any_cast
std::any(C++17)是一个类型擦除容器,std::any_cast 用于从中取回值。严格来说它们并不属于“类型转换 cast”家族,而是独立的类型工具。关于 std::any 的完整用法、类型擦除原理,以及与之配对的 std::variant,请参阅 C++17 any 与 variant。
比较与总结
| 转换类型 | 用途 | 安全性 | 运行时检查 | 典型场景 |
|---|
static_cast | 基本类型转换、向上转换、用户定义转换 | 中等 | 否 | 类型明确、安全的转换 |
dynamic_cast | 多态类型的向下转换 | 高 | 是 | 类层次结构中的运行时类型检查 |
const_cast | 移除/添加 const 或 volatile 限定符 | 低 | 否 | 处理 const 不匹配的遗留代码 |
reinterpret_cast | 不相关类型的低级别转换 | 低 | 否 | 硬件相关、指针/整数转换 |
选择建议
- 优先使用
static_cast:在类型关系明确且安全的场景下使用,性能较高。 - 使用
dynamic_cast 处理多态:当需要运行时类型检查时,特别是在类层次结构中。 - 谨慎使用
const_cast:仅在处理 const 不匹配的场景(如遗留代码)时使用。 - 尽量避免
reinterpret_cast:除非涉及底层编程或明确知道后果。