# 现代C++强制类型转换

在C++中,提供了四种特定的强制类型转换操作符,以提供更安全、更明确的类型转换,它们分别是 static_castdynamic_castconst_castreinterpret_cast

# static_cast:用于“良性”和“相关”的转换

static_cast 在编译期进行类型检查,如果转换在编译期被认为是无效的,则会引发错误。它适用于大部分良性的、有逻辑关联的类型转换。

# 核心特点

特性 描述
转换时机 编译期 (Compile-time)
安全性 部分安全。编译期会检查类型是否相关,但不进行运行时检查。
开销 无运行时开销,与C风格转换相当。

# 主要用途

  1. 基本数据类型转换
    适用于数值类型之间的转换,如 intdouble,或者 enumint

    double pi = 3.14159;
    int truncated_pi = static_cast<int>(pi); // 结果为 3
  2. 有继承关系的类指针/引用转换

    • 向上转型 (Upcasting):将派生类的指针或引用转换为基类,这是安全的,因为派生类包含了基类的所有成员。
    • 向下转型 (Downcasting):将基类的指针或引用转换为派生类。这是 不安全 的,因为它不进行运行时检查来确保基类指针确实指向一个派生类对象。如果转换错误,将导致未定义行为。
    class Base {};
    class Derived : public Base {};
    
    Derived d;
    // 向上转型:安全
    Base* b_ptr = static_cast<Base*>(&d);
    
    // 向下转型:不安全,程序员必须确保 b_ptr 确实指向一个 Derived 对象
    Derived* d_ptr = static_cast<Derived*>(b_ptr);
  3. void*指针转换为具体类型指针
    static_cast 可以将 void* 指针转回其原始或兼容的类型。

    void* p = malloc(10);
    int* int_p = static_cast<int*>(p);
    free(int_p);

# dynamic_cast:用于“安全”的向下转型

dynamic_cast 专门用于处理涉及多态(polymorphism)的类层次结构中的类型转换。它在运行时进行类型检查,以确保转换的安全性。

# 核心特点

特性 描述
转换时机 运行时 (Run-time)
安全性 安全。通过运行时类型信息 (RTTI) 检查转换的有效性。
开销 有运行时开销,比 static_cast 慢。
前提条件 只能用于包含虚函数(virtual function)的类,即多态类。

# 主要用途

  • 安全的向下转型:在类继承结构中,安全地将基类指针或引用转换为派生类指针或引用。

  • 转换失败的处理

    • 对于指针类型,如果转换失败,它会返回 nullptr
    • 对于引用类型,如果转换失败,它会抛出 std::bad_cast 异常。

<!-- end list -->

class Base { public: virtual ~Base() {} }; // 必须有虚函数
class Derived : public Base { public: void derived_only_func() {} };
class Another : public Base {};

void process(Base* b_ptr) {
    // 尝试将基类指针安全地转换为派生类指针
    if (Derived* d_ptr = dynamic_cast<Derived*>(b_ptr)) {
        // 转换成功,b_ptr 确实指向一个 Derived 或其子类的对象
        d_ptr->derived_only_func();
    } else {
        // 转换失败,b_ptr 指向的不是 Derived 对象
        // 在这里安全地处理其他情况
    }
}

# const_cast:用于移除 constvolatile 属性

const_cast 是唯一能修改类型的 constvolatile 限定符的转换符。它的主要使用场景是与一些旧的、未正确使用 const 的API交互。

# 核心特点

特性 描述
转换时机 编译期 (Compile-time)
安全性 不安全。如果试图通过 const_cast 移除 const 后去修改一个本身被定义为 const 的对象,将导致未定义行为。
开销 无运行时开销。

# 主要用途

  • 移除 const:将 const 指针/引用转换为非 const 指针/引用。
  • 添加 const:将非 const 指针/引用转换为 const 指针/引用。
// 一个老旧的C风格API,它不会修改数据,但参数不是 const
void legacy_c_api(char* str) {
    // ...
}

void call_legacy_api() {
    const char* my_str = "hello";
    // my_str 是 const,不能直接传递给 legacy_c_api
    // 我们确信 API 不会修改它,因此使用 const_cast
    legacy_c_api(const_cast<char*>(my_str));
}

警告:只有当你知道被转换的对象最初不是 const 时,才能安全地通过 const_cast 后的指针修改它。

# reinterpret_cast:用于处理“无关”类型的转换

reinterpret_cast 是最危险的类型转换,它执行底层的、与实现相关的位模式重新解释。编译器不会进行任何类型检查,完全信任程序员的操作。

# 核心特点

特性 描述
转换时机 编译期 (Compile-time)
安全性 极度不安全。它仅仅是重新解释内存中的位,结果是平台相关的。
开销 无运行时开销。

# 主要用途

只在非常底层的编程中才需要它,比如:

  • 指针与整数之间的转换:如将指针地址存为一个整数。
  • 不同类型的指针转换:在不相关的类型之间进行指针转换,例如将一个 int* 转换为 MyClass*
  • 与硬件交互:将一个特定的整数地址转换为设备寄存器的指针。
// 场景:将一个对象地址存为整数,之后再转回来
class MyClass {};
MyClass obj;

// 将指针地址转换为整数类型 uintptr_t
uintptr_t addr = reinterpret_cast<uintptr_t>(&obj);

// ... 在某个时刻 ...

// 将整数地址转回原始指针类型
MyClass* obj_ptr = reinterpret_cast<MyClass*>(addr);

// 场景:字节流的重新解释
char buffer[sizeof(MyClass)];
// ... 从网络或文件读取字节到 buffer ...
MyClass* p_obj_from_buffer = reinterpret_cast<MyClass*>(buffer);

# 四种转换总结

转换类型 转换时机 安全性 主要用途
static_cast 编译期 部分安全 相关类型转换(数值、继承、void*)
dynamic_cast 运行时 安全 多态类层次结构中的安全向下转型
const_cast 编译期 不安全 添加或移除 const / volatile 属性
reinterpret_cast 编译期 极度不安全 底层、无关类型的位模式重新解释