C++的四种强制转换

static_cast

static_cast 是最常用的类型转换形式,用于各种明确的类型转换,如基本数据类型的转换(例如从 floatint),或类层次结构中基类与派生类之间的转换(仅当存在明确的继承关系时)。

  • 用途
    • 转换数值类型,例如整数和浮点数之间。
    • 将派生类指针或引用转换为基类指针或引用,反之亦然(只要没有虚继承且路径明确)。
    • 调用有显式类型转换的构造函数或转换操作符。
  • 特性
    • 无运行时类型检查static_cast 在编译时进行类型检查,不提供运行时类型安全保障。这意味着,如果进行不适当的转换(如向下转换到一个实际不是该类型的对象),编译器可能不会报错,但程序运行时可能会导致错误或未定义行为。
    • 上行转换是安全的:将派生类的指针或引用转换为基类的指针或引用通常是安全的,因为派生类对象总是包含基类部分。
    • 下行转换是不安全的:将基类的指针或引用转换为派生类的指针或引用在没有运行时类型检查的情况下是不安全的,因为基类对象可能实际上不是派生类对象。
  • 使用场景
    • 基本数据类型转换static_cast 可以用于基本数据类型之间的转换,例如将 int 转换为 char,或者 double 转换为 int。这种转换会根据需要进行适当的数值截断或转换。
      int i = 10;
      char c = static_cast<char>(i);
      
    • 将任何类型的表达式转换成 void 类型:这允许将任何表达式转换为 void 类型,通常用于忽略表达式的值,如在宏定义中使用。
      int x = 10;
      static_cast<void>(x);  // 用于显式忽略x的值
      
    • 类层次结构中的转换
      • 上行转换(安全):将派生类转换为基类。
      • 下行转换(不安全):将基类转换为派生类,不推荐使用,除非确保转换是安全的。
        class Base {};
        class Derived : public Base {};
        
        Derived d;
        Base* bp = &d;  // 隐式转换,也可以显式用static_cast
        Derived* dp = static_cast<Derived*>(bp);  // 风险操作,仅当确定bp确实指向Derived时使用
        
  • 注意事项
    • 尽管 static_cast 在编译时提供了一定程度的类型检查,但它不能保证转换的运行时安全性,尤其是在涉及复杂类层次结构的转换时。在使用 static_cast 进行下行转换时,开发者需要确保转换的安全性,否则可能会引发运行时错误。在需要运行时检查的情况下,应该使用 dynamic_cast
  • 示例
    double d = 9.23;
    int i = static_cast<int>(d);  // 基本类型转换
    
    class Base {};
    class Derived : public Base {};
    
    Derived* dp = new Derived();
    Base* bp = static_cast<Base*>(dp);  // 向上转换
    

dynamic_cast

dynamic_cast 主要用于类层次结构中,安全地将基类指针或引用转换为派生类指针或引用,并在运行时检查转换的有效性(使用RTTI,即运行时类型信息)。它只能用于包含虚函数的类。

  • 用途
    • 安全地将基类指针或引用转为派生类指针或引用,当转换无效时,指针转换返回 nullptr,引用转换抛出 std::bad_cast 异常。
  • 特性
    • 类型安全的下行转换dynamic_cast 用于类层次结构中的下行转换(将基类指针或引用转换为派生类指针或引用)时,它提供运行时类型检查,确保转换的目标类型是正确的。这种检查是基于对象的实际类型,不仅仅是它被声明的类型。
    • 基于虚函数的运行时类型信息 (RTTI):为了使 dynamic_cast 能够执行这些运行时检查,基类需要至少有一个虚函数。这是因为虚函数的存在使得编译器为该类生成RTTI,dynamic_cast 使用这些信息来检查和确认转换的有效性。
    • 转换目标
      • 可以转换为类的指针、引用或者 void*。对于类的指针和引用,dynamic_cast 主要用于安全地进行下行转换。
      • 转换为 void* 主要用于获取指向对象的最底层基类部分的指针。
    • 转换结果
      • 对于指针:如果转换失败(即如果尝试转换的类型与实际对象的类型不兼容),dynamic_cast 返回 nullptr
      • 对于引用:如果转换失败,会抛出 std::bad_cast 异常。
  • 示例
    • 假设有一个类层次结构,其中 Base 类有一个虚函数,DerivedBase 的一个派生类:
      #include <iostream>
      #include <typeinfo>  // For std::bad_cast
      
      class Base {
      public:
      	virtual void print() { std::cout << "Base class" << std::endl; }
      	virtual ~Base() {}
      };
      
      class Derived : public Base {
      public:
      	void print() override { std::cout << "Derived class" << std::endl; }
      };
      
      int main() {
      	Base* b = new Derived();  // 向上转换,安全
      	try {
      		Derived* d = dynamic_cast<Derived*>(b);  // 向下转换,安全
      		if (d) {
      			d->print();  // 成功调用
      		} else {
      			std::cout << "Conversion failed." << std::endl;
      		}
          
      		Base* b2 = new Base();  // 基类对象
      		Derived* d2 = dynamic_cast<Derived*>(b2);  // 转换失败,返回nullptr
          	if (d2) {
      			d2->print();
      		} else {
      			std::cout << "Conversion failed." << std::endl;
      		}
          
      		Base& b3 = *b2;
      		Derived& d3 = dynamic_cast<Derived&>(b3);  // 引用转换失败,抛出异常
      		d3.print();
      	} catch (const std::bad_cast& e) {
      		std::cout << "Bad cast: " << e.what() << std::endl;
      	}
      	delete b;
      	delete b2;
      	return 0;
      }
      
  • 注意事项
    • dynamic_cast 在运行时检查的能力使其在需要确保类型安全的场景中非常有用,但这也意味着与其他更简单的转换(如 static_cast)相比,它的性能成本较高。
    • 在设计时应当注意,过度依赖 dynamic_cast 可能暗示设计上存在问题,可能需要重新考虑类的设计和接口。
    • dynamic_cast 不能用于基本数据类型的转换。dynamic_cast 主要用于对象的指针和引用之间的转换,特别是在涉及类层次结构中的对象时。它需要运行时类型信息(RTTI)来检查转换是否安全,这种信息仅在类类型的对象中可用,因为它们涉及到虚函数。
    • 对于基本数据类型,如 intfloatchar 等,你应该使用 static_cast 来进行转换。static_cast 提供了足够的功能来处理基本类型之间的转换,并且效率更高,因为它不涉及运行时类型检查。例如,如果你需要将 double 转换为 int,你应该使用 static_cast,如下所示:
      double d = 9.57;
      int i = static_cast<int>(d);  // 将 double 转换为 int
      
  • 示例
    class Base { virtual void dummy() {} };
    class Derived : public Base { int a; };
    Base* bp = new Derived();
    Derived* dp = dynamic_cast<Derived*>(bp);  // 安全向下转换
    if (dp) {
        // 转换成功
    }
    

reinterpret_cast

reinterpret_cast 提供了低层次的强制类型转换,它可以将任何指针类型转换为任何其他指针类型,甚至可以将指针转换为足够大的整数类型。此转换的安全性和便携性不保证,应谨慎使用。

  • 用途
    • 用于位的简单重新解释,如指针与整数之间的转换。
    • 可以将整型转换为指针,也可以把指针转换为数组;可以在指针和引⽤⾥进⾏肆⽆忌惮的转换,平台移植性⽐价差。
    • 将一个指针转换为不相关类型的指针。
  • 示例
    long p = 0x12345678;
    char* cp = reinterpret_cast<char*>(&p);  // 将long指针转换为char指针
    

const_cast

const_cast 用于修改类型的 constvolatile 属性。它是唯一能够去除对象的 const(或添加)的C++类型转换操作符。

  • 用途
    • 用于添加或去除对象的 constvolatile 属性。
  • 示例
    const int ci = 10;
    int* modifiable = const_cast<int*>(&ci);
    *modifiable = 20;  // 未定义行为,如果原始对象是常量
    
  • 27
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LIHAORAN99

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值