C++ 四种类型转换

C++中的四种类型转换分别为:static_cast,const_cast,reinterpret_cast,dynamic_cast。

=========================================================================

1.static_cast 静态转换

这是最常用、最通用的转换运算符,用于在"有理由"相互关联的类型之间进行转换。

static_cast 在编译时 使用类型信息执行转换,在转换执行必要的检测(如指针越界计算,类型检查等);但没有 运行时 类型检查来保证转换的安全性。

主要用途:

基本数据类型之间的转换 (例如 int 转 double, enumint)。

cpp

int i = 10;

double d = static_cast<double>(i); // 将整数i转换为双精度浮点数d
2.

void 指针 与其他具体类型指针之间的转换。

cpp

void* ptr = malloc(100);

int* iptr = static_cast<int*>(ptr); // 将void*转换为int* 2.1//注意! 指针转换的限制 //不能去除掉const等特性 //具体指针类型不同不可以转换

volatile - 易变限定符

volatile 告诉编译器该变量可能会在程序控制之外被改变,因此编译器不应对其进行优化。

__unaligned - 非对齐限定符

用于告诉编译器该数据可能没有按照处理器的自然对齐方式存储,需要特殊处理。

注意__unaligned 不是标准的 C++ 关键字,而是某些编译器(主要是 Microsoft VC++)的扩展。

3.类层次结构中的向上转换 (Upcasting)

将派生类指针或引用转换为基类指针或引用。这是安全的,编译器会自动进行,但显式使用 static_cast 也可以。

  1. cpp

    class Base {};

    class Derived : public Base {};

    Derived d;

    Base* b = static_cast<Base*>(&d); // 安全,向上转换

//类层次结构中的向下转换 (Downcasting):将基类指针或引用转换为派生类指针或引用。这是不安全的 ,因为编译器无法在编译时确定指针所指的实际对象类型。如果使用 static_cast 进行向下转换,需要程序员自己确保转换是安全的。如果不安全,会导致未定义行为。
  1. cpp

  2. Base* b = new Derived; // 实际上指向一个Derived对象

  3. Derived* d = static_cast<Derived*>(b); // 编译通过,但风险由程序员承担

4.显示的弃值表达式

弃值表达式 是指在 C++ 中表达式被求值,但其结果被有意丢弃而不使用的表达式。

cpp

int main()

{

int a = 10, b = 20;

static_cast<void>(a+b); // 这就是一个弃值表达式

}

第4行 static_cast<void>(a+b) 就是一个典型的弃值表达式:

  • 计算 a + b 得到结果 30

  • 使用 static_cast<void> 明确表示我们故意要丢弃这个值

  • 整个表达式的结果被丢弃,不赋值给任何变量,也不用于任何计算

5.左值到右值的转换

cpp

int main()

{

int a=10;

int &x=a;

int && rx=a;//erro

int && rx=static_cast<int&&>(a);

}

特点:

  • 转换在编译期完成。

  • 不能移除 constvolatile 属性(这是 const_cast 的工作)。

=========================================================================

2.const_cast 常量转换

这是唯一一个有能力移除或添加 对象的 const(常量)或 volatile(易变)属性的转换运算符。

主要用途:

  1. 移除 const 属性 :用于修改一个原本不是 const (指针,引用等等)但被声明为 const (常量指针,常量引用等等)的变量。

    cpp

    void print(char* str) { // 一个不接受const指针的函数

    std::cout << str << std::endl;

    }

    const char* greeting = "Hello, World!";

    // print(greeting); // 错误!不能将const char*传递给char*

    print(const_cast<char*>(greeting)); // 正确,移除了const

    重要警告 :如果原始对象本身就是一个常量(字符串常量等等),通过 const_cast 修改它是未定义行为

    cpp

    const int ci = 10;

    int* modifiable = const_cast<int*>(&ci);

    *modifiable = 20; // 未定义行为!可能导致程序崩溃或意外结果

特点:

特点:

  • 不能用于在不同类型之间进行转换(例如 intdouble),只能修改类型的 const/volatile 属性。

  • 常量指针被转化为非常量指针,仍然指向原来的对象

  • 常量引用被转换为非常量引用,仍然引用原来的对象======================================================================

    3.reinterpret_cast 重新解释转换

    这是最危险 的转换,它提供了底层的、基于比特位的重新解释。它仅仅将一块内存的二进制数据当作另一种完全不同的类型来处理,不进行任何类型检查。

    主要用途:

  • 在不相关类型的指针之间转换 (例如 int*double*)。

  • 在指针和整型之间转换

    cpp

    复制代码
    int* p = new int(65);
    char* ch = reinterpret_cast<char*>(p); // 将int*强行解释为char*
    std::cout << *ch << std::endl; // 输出 'A',因为65是'A'的ASCII码
    
    // 将指针转换为一个足够大的整数(例如uintptr_t)
    uintptr_t addr = reinterpret_cast<uintptr_t>(p);
  • 转换结果几乎总是依赖于编译器实现,不可移植

  • 极其危险,必须非常清楚自己在做什么,并且确保转换是合乎逻辑的。

  • 通常用于底层编程,如驱动、序列化、网络协议等场景

=========================================================================

4. dynamic_cast 动态转换

专门用于处理多态 (涉及虚函数)的类层次结构的安全向下转换。

主要用途:

  1. 安全的向下转换 :将基类指针或引用安全地转换为派生类指针或引用,具有类型检查,比static_cast 更安全。//在进行上行转换时,dynamic_cast 和static_cast 的效果是一样的。

  2. 交叉转换 (Cross Casting):在多重继承中,将一个基类指针转换为另一个不直接相关的基类指针。

-----对于 上行转换 共有继承,无虚函数(无虚表,无RTTI) 的情况,为静态转换,dynamic_cast 和static_cast 的效果一样。

-----对于 下行转换情况,需公有继承,至少有一个虚函数。

执行过程是 先找到对象,再找虚表,再判断RTII //动态转换

如果没有虚函数,则在编译时则停止

//如 Base 有两个派生类 Derived 和 AnotherDerived:

当进行向下转换时,如果Base 已经指向了某个派生类 如 Base* basePtr1 = new Derived();(即提前进行过向上转换),则再进行向下转换时,Base只能被成功转换为和之前指向的派生类相同类型的派生类 如 Derived,而不能被转换为其他的派生类 如 AnotherDerived。

如果转换失败,static_cast会导致未定义行为,而dynamic_cast会返回空,或抛出异常。

(这也是两者之间的区别)

cpp 复制代码
class Base {
public:
    virtual ~Base() {}
    virtual void foo() { cout << "Base::foo" << endl; }
};

class Derived : public Base {
public:
    void foo() override { cout << "Derived::foo" << endl; }
    void derivedMethod() { cout << "Derived特有方法" << endl; }
};

class AnotherDerived : public Base {
public:
    void foo() override { cout << "AnotherDerived::foo" << endl; }
};

场景分析

场景1:正确的转换
cpp 复制代码
Base* basePtr = new Derived();  // 实际指向Derived对象
Derived* derivedPtr = static_cast<Derived*>(basePtr);  // ✅ 安全
derivedPtr->derivedMethod();  // ✅ 正常工作

发生了什么

  • static_cast 在编译时直接进行指针偏移计算

  • 由于实际对象确实是 Derived 类型,转换是正确的

  • 虚表指针保持不变,虚函数调用正常

场景2:错误的转换(危险!)
cpp 复制代码
Base* basePtr = new AnotherDerived();  // 实际指向AnotherDerived
Derived* derivedPtr = static_cast<Derived*>(basePtr);  // ❌ 危险!
derivedPtr->derivedMethod();  // ❌ 未定义行为!

会发生什么

  • static_cast 仍然会进行指针偏移计算

  • 但实际对象是 AnotherDerived,没有 derivedMethod

  • 调用 derivedMethod() 会导致未定义行为

    • 可能崩溃

    • 可能执行错误代码

    • 可能破坏内存

技术实现差异

特性 static_cast dynamic_cast
检查时机 编译时 运行时
检查机制 无类型检查 通过RTTI和虚表检查
失败行为 未定义行为 返回nullptr(指针)或抛异常(引用)
性能 零运行时开销 有运行时开销
安全性 不安全 安全
适用场景 确定类型正确的场景 不确定类型,需要安全检查的场景

工作机制:

它在运行时 利用 RTTI 来检查转换的有效性。

  • 对于指针 类型:如果转换成功,返回目标类型的指针;如果失败(例如,基类指针并不指向目标派生类对象),则返回 nullptr。

    cpp

    复制代码
    class Base { public: virtual ~Base() {} }; // 必须有虚函数
    class Derived : public Base {};
    
    Base* b1 = new Derived; // 实际指向Derived
    Base* b2 = new Base;    // 实际指向Base
    
    Derived* d1 = dynamic_cast<Derived*>(b1); // 成功,d1指向有效的Derived对象
    Derived* d2 = dynamic_cast<Derived*>(b2); // 失败,d2是nullptr
    
    if(d2) { // 安全的做法:检查返回值
        // ... 使用d2
    } else {
        std::cout << "转换失败!" << std::endl;
    }
  • 对于引用 类型:如果转换失败,它会抛出一个 std::bad_cast 异常,因为引用不能为 null

    cpp

    复制代码
    try {
        Derived& rd = dynamic_cast<Derived&>(*b2); // 转换失败,抛出异常
    } catch (const std::bad_cast& e) {
        std::cerr << "转换失败: " << e.what() << std::endl;
    }

特点:

  • 唯一 在运行时进行类型检查的转换运算符。

  • 有运行时开销。

  • 要求基类至少有一个虚函数(这样才能有 RTTI 信息)。

RTTI(运行时类型识别)详解

定义:RTTI(Run-Time Type Identification)是一种机制,允许程序在运行时:

  • 确定指针或引用所指向对象的实际类型

  • 安全地进行类型转换

  • 获取类型的详细信息

核心思想:在面向对象编程中,通过基类指针或引用操作对象时,有时需要知道对象的具体派生类型。


RTTI 的两个核心操作符

  1. typeid 操作符

功能 :获取表达式的类型信息,返回一个 std::type_info 对象的引用。

typeid 的重要特性

  • 对于多态类型(有虚函数的类),返回动态类型(实际对象类型)

  • 对于非多态类型,返回静态类型(声明时的类型)

  • 可以用于类型比较和获取类型名称

2. dynamic_cast 操作符

功能:在类层次结构中安全地进行向下转换(downcast)或交叉转换(crosscast)。

dynamic_cast 的重要特性

转换类型 指针转换 引用转换
成功 返回目标类型指针 返回目标类型引用
失败 返回 nullptr 抛出 std::bad_cast 异常

相关推荐
卡提西亚2 小时前
C++笔记-9-三目运算符和switch语句
c++·笔记
CodeWizard~2 小时前
AtCoder Beginner Contest 430赛后补题
c++·算法·图论
喜欢吃燃面3 小时前
C++:哈希表
开发语言·c++·学习
mit6.8243 小时前
[C++] 时间处理库函数 | `tm`、`mktime` 和 `localtime`
开发语言·c++
SweetCode3 小时前
C++ 大数乘法
开发语言·c++
listhi5203 小时前
基于空时阵列最佳旋转角度的卫星导航抗干扰信号处理的完整MATLAB仿真
开发语言·matlab·信号处理
lly2024063 小时前
Kotlin 类和对象
开发语言
是苏浙3 小时前
零基础入门C语言之C语言内存函数
c语言·开发语言
zhmhbest4 小时前
Qt 全球峰会 2025:中国站速递 —— 技术中立,拥抱更大生态
开发语言·qt·系统架构