C/C++中类型转换:static_cast, dynamic_cast, const_cast, reinterpret_cast

2024-01-05 02:52

本文主要是介绍C/C++中类型转换:static_cast, dynamic_cast, const_cast, reinterpret_cast,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 目的
    • 定义和作用

目的

在C中一般是使用(int) x, (int *)x, (void *) p等方式,但是这种强制类型转换的方式是不安全的,因为他没有类型检查。而且这种转换也是不够精确的。
因此在C++中引入了几种强制类型转换的方式。

定义和作用

  1. static_cast:

    1. 提供安全的基本类型转换:但是要注意数据的截断或者改变。(float转换为整数的时候丢失小数部分)。
    2. 类层次间转换:
      向上转换(将派生类的指针/引用转换为基类的指针/引用),这是安全的,因为派生类总是包含基类的全部信息。
      向下转换(将基类的指针/引用转换为派生类的指针/引用),这是不安全的,因为基类不一定包含派生类的全部信息。
    3. 空指针转换为目标类型的空指针:
      class Base {};
      class Derived : public Base {};Base* b = nullptr;
      Derived* d = static_cast<Derived*>(b);  // 安全转换,d 仍然是 nullptr。
      
    4. non_const转换为const
      int x = 10;
      const int* px = static_cast<const int*>(&x);
      
  2. dynamic_cast:
    用于多态,尤其是向下转换和侧向转换(在同一层次结构中的不同类之间)。
    在执行转换时进行运行时检查。如果是安全的(即对象确实是目标类型或其派生类型的实例),则转换成功;如果不安全则转换失败(对于指针,返回nullptr,对于引用抛出异常。

    class Base { virtual void dummy() {} };
    class Derived : public Base { /* ... */ };Base* basePtr = new Derived();// 安全的向下转换
    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
    

    注意:

    1. 使用dynamin_cast必要要求设计的类至少有一个虚函数,因为涉及多态。
    2. 编译时无法确定转换结果,所以是运行时检查。

    补充侧向转换:
    指的是在同一继承层次中,将一个基类的指针或引用转换为另一个并行基类的指针或引用。
    这种转换通常发生在多重继承的情况下,当一个派生类继承自多个基类时。
    侧向转换的场景
    假设有一个多重继承的类层次结构,其中 Derived 类继承自两个基类 Base1 和 Base2:

    Copy code
    class Base1 { /* ... */ };
    class Base2 { /* ... */ };
    class Derived : public Base1, public Base2 { /* ... */ };
    

    在这种结构中,Derived 同时是 Base1 和 Base2 的子类。如果你有一个指向 Base1 的指针,且它实际上指向的是一个 Derived 类型的对象,你可以使用侧向转换将这个指针安全地转换为指向 Base2 的指针:

    Copy code
    Derived d;
    Base1* b1 = &d;
    Base2* b2 = dynamic_cast<Base2*>(b1); // 侧向转换
    

在这个例子中,dynamic_cast 被用来从 Base1 类型转换到 Base2 类型。由于这两个类是在同一个继承层次中,这样的转换是可能的,并且如果 b1 确实指向一个 Derived 类型的对象,转换将会成功。

  1. const_cast:
    去除对象指针/引用的const属性
    const_cast 是 C++ 中的一种类型转换操作符,专门用于修改对象的 constvolatile 属性。它是用来改变对象的常量性(const-ness)或易失性(volatility)的。
    使用场景与目的

    1. 移除 constvolatile 限定:

      • 当你有一个指向常量的指针或引用,但需要调用一个非常量成员函数或需要修改其指向的数据时,可以使用 const_cast 来移除 constvolatile 限定。
      • 这常用于与旧的C风格代码交互,其中数据不是常量,但接口要求传递常量参数。
    2. 添加 const 限定:

      • 虽然不常见,但 const_cast 也可以用来给对象添加 const 限定。这在某些特定情况下可能有用。
        使用示例
    const int a = 10;
    int* b = const_cast<int*>(&a);  // 移除 const 限定
    *b = 20;  // 未定义行为,因为 a 是一个真正的常量
    

    在此例中,尽管 const_cast 成功移除了 const 限定,但对 a 的修改是未定义行为,因为 a 本身是一个常量。

    局限(缺点)

    1. 未定义行为风险:
      如果原始对象实际上是一个常量,尝试修改它的值(即使使用 const_cast 移除了 const 限定)将导致未定义行为。

    2. 安全性问题:
      滥用 const_cast 可能导致代码难以理解和维护,因为它破坏了 const 正确性,这是 C++ 用于保证对象不被意外修改的机制之一。

    3. 限制用途:
      const_cast 只能改变对象的 const/volatile 限定,不能用于改变对象的实际类型。

    4. 破坏封装性:
      在类的上下文中,const_cast 可能会破坏类的封装性,因为它允许修改本应被保护的成员。

  2. reinterpret_cast:
    它用于在不兼容类型之间进行转换,基本上是直接重新解释底层的位模式。由于这种转换的低级性质,它通常在特定的系统编程和硬件相关的场景中使用。

    使用场景与目的

    1. 不兼容类型之间的转换:
      用于在完全不相关的类型之间进行转换,例如将指针转换为足够大的整数类型,或将不同类型的指针之间进行转换。
    2. 系统级或硬件相关编程:
      在底层编程中,如操作系统内核或硬件接口编程时,可能需要将指针或其他类型直接转换为某种特定格式。
    3. 函数指针的转换:
      用于将一个类型的函数指针转换为另一个类型。这在需要将函数指针传递给期望不同签名的函数指针参数的回调函数时特别有用。
      示例
    Copy code
    int* ip = new int(42);
    char* cp = reinterpret_cast<char*>(ip);  // 将 int* 转换为 char*
    

    在此示例中,ip 指向一个整数,使用 reinterpret_cast 将其转换为指向 char 的指针。

    局限(缺点)

    1. 类型安全问题:
      reinterpret_cast 不进行任何类型安全检查。它简单地重新解释给定值的位模式,这可能导致未定义行为,特别是在不恰当地解释数据时。
    2. 可移植性问题:
      由于它依赖于特定平台的底层数据表示方式,所以使用 reinterpret_cast 的代码通常缺乏可移植性。
    3. 维护性和可读性问题:
      这种转换的意图不够明确,可能导致代码难以理解和维护。
    4. 潜在的运行时错误:
      错误的使用 reinterpret_cast 可能导致程序崩溃、数据损坏或其他难以调试的运行时错误。
  3. 违反别名规则:
    在某些情况下,reinterpret_cast 可能违反 C++ 的严格别名规则(Strict Aliasing Rule),这可能导致编译器优化产生问题。

这篇关于C/C++中类型转换:static_cast, dynamic_cast, const_cast, reinterpret_cast的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/571435

相关文章

C++ HTTP框架推荐(特点及优势)

《C++HTTP框架推荐(特点及优势)》:本文主要介绍C++HTTP框架推荐的相关资料,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Crow2. Drogon3. Pistache4. cpp-httplib5. Beast (Boos

C++类和对象之初始化列表的使用方式

《C++类和对象之初始化列表的使用方式》:本文主要介绍C++类和对象之初始化列表的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C++初始化列表详解:性能优化与正确实践什么是初始化列表?初始化列表的三大核心作用1. 性能优化:避免不必要的赋值操作2. 强

C++迭代器失效的避坑指南

《C++迭代器失效的避坑指南》在C++中,迭代器(iterator)是一种类似指针的对象,用于遍历STL容器(如vector、list、map等),迭代器失效是指在对容器进行某些操作后... 目录1. 什么是迭代器失效?2. 哪些操作会导致迭代器失效?2.1 vector 的插入操作(push_back,

C#如何调用C++库

《C#如何调用C++库》:本文主要介绍C#如何调用C++库方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录方法一:使用P/Invoke1. 导出C++函数2. 定义P/Invoke签名3. 调用C++函数方法二:使用C++/CLI作为桥接1. 创建C++/CL

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

python中各种常见文件的读写操作与类型转换详细指南

《python中各种常见文件的读写操作与类型转换详细指南》这篇文章主要为大家详细介绍了python中各种常见文件(txt,xls,csv,sql,二进制文件)的读写操作与类型转换,感兴趣的小伙伴可以跟... 目录1.文件txt读写标准用法1.1写入文件1.2读取文件2. 二进制文件读取3. 大文件读取3.1

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve