C++中的四种cast详解

182 阅读6分钟

C++中的四种cast详解

公众号:阿Q技术站

1. static_cast

作用static_cast 用于在编译时进行类型转换。它用于普通的类型转换,支持基本类型之间的转换(如 intfloat),以及在有继承关系的类之间的转换(如基类和派生类之间的转换)。

使用场景

  • 基本数据类型之间的转换:例如,将 int 转换为 double
  • 类层次结构中的上行转换(从派生类到基类):这种转换是安全的,因为派生类对象可以安全地视为基类对象。static_cast不能用于下行转换(从基类到派生类),因为这需要运行时检查以确保安全性,此时应使用dynamic_cast
  • void*指针转换为其他类型的指针:static_cast可以将void*指针转换回任何类型的指针。
  • 去除 const 属性:虽然 const_cast 更适合去除 const 属性,但 static_cast 也可以用于某些场景。

底层原理static_cast 通常通过编译时检查来保证转换合法,能够在编译时确定类型之间的关系。对于类之间的转换,它依赖于类的继承层次。

用法示例

#include <iostream>class Base {};
class Derived : public Base {};
​
int main() {
    // 基本数据类型之间的转换
    double d = 3.14;
    int i = static_cast<int>(d);
    std::cout << "Double to Int: " << i << std::endl;
​
    // 指针和引用之间的转换
    Derived dObj;
    Base& bRef = static_cast<Base&>(dObj);  // 上行转换,安全
    Base* bPtr = &dObj;
    Derived* dPtr = static_cast<Derived*>(bPtr);  // 下行转换,不安全
​
    // void* 指针的转换
    int value = 42;
    void* voidPtr = &value;
    int* intPtr = static_cast<int*>(voidPtr);
    std::cout << "Value: " << *intPtr << std::endl;
​
    return 0;
}

注意事项

  • 如果进行非法的转换(比如将一个不相关的类指针转换为另一个类指针),编译器会给出错误提示。
  • 不会进行空指针检查,因此需要手动确保转换的安全性。

2. dynamic_cast

作用:用于类层次结构中的下行转换(从基类到派生类),并且提供了运行时类型检查。如果转换失败,对于指针类型返回 nullptr,对于引用类型抛出 std::bad_cast 异常。 这种转换只能用于包含虚函数的类(即多态类型),因为它们需要运行时类型信息(RTTI)来检查转换的安全性。

使用场景

  • 用于多态类型转换,尤其是进行类之间的向下转换(Base* 转为 Derived*)。
  • 如果类型不匹配,dynamic_cast 会返回 nullptr(对于指针转换)或者抛出 std::bad_cast 异常(对于引用转换)。

底层原理dynamic_cast 需要通过运行时类型信息(RTTI)来执行转换。它会在程序运行时检查类型,并在转换不合法时提供错误处理。这个机制使得 dynamic_cast 相比 static_cast 更加安全。

用法示例

#include <iostream>
#include <typeinfo>class Base {
public:
    virtual ~Base() {}  // 必须有虚函数
};
​
class Derived : public Base {};
​
int main() {
    Base bObj;
    Derived dObj;
    Base* bPtr = &bObj;
    Base* bPtr2 = &dObj;
​
    // 安全的下行转换
    Derived* dPtr = dynamic_cast<Derived*>(bPtr2);
    if (dPtr) {
        std::cout << "Downcast successful" << std::endl;
    } else {
        std::cout << "Downcast failed" << std::endl;
    }
​
    // 不安全的下行转换
    dPtr = dynamic_cast<Derived*>(bPtr);
    if (dPtr) {
        std::cout << "Downcast successful" << std::endl;
    } else {
        std::cout << "Downcast failed" << std::endl;
    }
​
    return 0;
}

注意事项

  • dynamic_cast 只能用于有虚函数的类,确保编译器生成了 RTTI 信息。
  • 对于指针类型的转换,如果转换失败,dynamic_cast 会返回 nullptr,你需要检查这个返回值。
  • 对于引用类型的转换,如果转换失败,dynamic_cast 会抛出 std::bad_cast 异常。

3. const_cast

作用const_cast 用于在常量和非常量之间进行转换。它允许你去除或者添加对象的 const 限定符。可以用于改变指针或引用的常量性,但不能改变对象本身的常量性。

使用场景

  • 用于将常量指针或常量引用转换为非 const 类型。
  • 去掉常量性时要小心,避免修改原本应该是常量的数据。

底层原理const_cast 在编译时操作类型,仅仅是通过改变指针或引用的常量性,而不会修改数据本身。对于去除 const 后的修改行为,编译器不会检查数据是否被修改,因此必须确保修改的对象是允许修改的。

用法示例

#include <iostream>int main() {
    const int value = 42;
    int* nonConstPtr = const_cast<int*>(&value);
    *nonConstPtr = 100;  // 修改原来的常量值,不推荐这样做
    std::cout << "Modified value: " << value << std::endl;  // 输出可能未定义
​
    return 0;
}

注意事项

  • 只用于指针和引用类型的转换。
  • 对于 const_cast 去除 const 后,修改原本为 const 的数据是未定义行为(UB),即你不能去除 const 并修改数据,除非原始数据本身允许修改。

4. reinterpret_cast

作用reinterpret_cast 用于进行低级别的类型转换,可以将一个指针类型转换为任何其他的指针类型,或者将任何其他类型的指针转换为 void*,甚至可以进行指针与整数之间的转换。

使用场景

  • 用于指针的转换或在需要与底层硬件交互时进行类型转换。
  • 例如,将一个整数转换为一个指针,或将一个指针转换为一个不同类型的指针。

底层原理reinterpret_cast 是一种非常低级的转换,它将类型重新解释为另一种类型,不做任何类型的检查,只是简单地重新解释指针或整数的二进制表示。它可以进行非常规的类型转换,甚至跨越不同的类型体系。

用法示例

#include <iostream>int main() {
    int value = 42;
    void* voidPtr = &value;
    int* intPtr = reinterpret_cast<int*>(voidPtr);
    std::cout << "Value: " << *intPtr << std::endl;
​
    // 指针和整数之间的转换
    int* ptr = &value;
    uintptr_t intPtrValue = reinterpret_cast<uintptr_t>(ptr);
    std::cout << "Pointer as integer: " << intPtrValue << std::endl;
​
    // 不同类型的指针之间的转换
    class A {};
    class B {};
    A aObj;
    B* bPtr = reinterpret_cast<B*>(&aObj);  // 不安全的转换
​
    return 0;
}

注意事项

  • 非常危险reinterpret_cast 在转换时不会进行类型检查,因此非常容易导致未定义行为(UB),需要特别小心。
  • 一般建议避免滥用,除非你有非常特殊的需求(如底层系统编程、硬件编程等)。
  • 对于指针类型的转换,reinterpret_cast 可能破坏对象的类型信息,导致内存访问错误。

总结

类型转换说明适用场景安全性
static_cast编译时类型转换,用于基本类型、类层次结构间的转换适用于类型之间的显式转换,继承关系的转换安全,编译时检查,转换合法性由编译器保证
dynamic_cast运行时类型转换,用于多态类型之间的转换(基类和派生类)用于多态类型的安全转换安全,运行时检查,转换失败时返回 nullptr
const_cast去除或添加常量性,改变指针或引用的 const 限定符用于修改 const 限定符的指针或引用安全,但修改 const 数据是未定义行为
reinterpret_cast低级类型转换,可以进行指针和整数之间的转换用于底层操作,如硬件编程、与不同类型的交互非常危险,极易引发未定义行为