C++ 类型转换及 UB(未定义行为)

C++ 中的四种类型转换运算符(static_castdynamic_castconst_castreinterpret_cast)及其正确使用场景

1. static_cast(静态转换)

static_cast 是 C++ 提供的 编译时(静态)类型转换,主要用于已知安全的类型转换。它比 C 风格 (T)value 更加安全,具有更明确的语义,并在编译时进行类型检查.

1.1 正确用法:基本数据类型转换

#include <iostream>
int main() {
    double d = 3.14;
    int i = static_cast<int>(d);  // 将 double 转换为 int
    std::cout << "i = " << i << std::endl;  // 输出:3
    return 0;
}

1.2 正确用法:基类与派生类之间的向上转换

#include <iostream>
class Base {
public:
    virtual ~Base() {} // 为 dynamic_cast 保证多态
};

class Derived : public Base {};

int main() {
    Derived d;
    // 向上转换:从 Derived* 转为 Base*
    Base* b = static_cast<Base*>(&d);
    std::cout << "Base pointer: " << b << std::endl;
    return 0;
}

1.3 UB 案例:错误的向下转换

如果将一个 Base 对象错误地转换为 Derived 类型,将导致 UB。

#include <iostream>
class Base {};
class Derived : public Base {};

int main() {
    Base b;
    // 错误:Base 对象并不包含 Derived 的信息
    Derived* d = static_cast<Derived*>(&b);  // UB:不正确的向下转换
    // 这里 d 指向的数据不包含 Derived 的特有部分,后续使用 d 可能导致崩溃或错误
    return 0;
}

2. dynamic_cast(动态转换)

dynamic_cast 是 C++ 运行时类型转换(RTTI, Run-Time Type Information) 机制的一部分,主要用于基类和派生类之间的转换,尤其是 安全的向下转换(Base → Derived)。

2.1 正确用法:向下转换(需要多态类型)

#include <iostream>
class Base {
public:
    virtual ~Base() {} // 必须有虚函数
};

class Derived : public Base {
public:
    void hello() { std::cout << "Hello from Derived!" << std::endl; }
};

int main() {
    Base* b = new Derived();
    // 尝试将 Base* 动态转换为 Derived*
    Derived* d = dynamic_cast<Derived*>(b);
    if (d) {
        d->hello();  // 转换成功,调用 Derived 的方法
    } else {
        std::cout << "Conversion failed." << std::endl;
    }
    delete b;
    return 0;
}

2.2 UB 案例:对非多态类型使用 dynamic_cast

如果基类没有虚函数,则 dynamic_cast 无法执行正确的运行时检查,结果将是 UB。

#include <iostream>
class Base { /* 没有虚函数 */ };
class Derived : public Base {};

int main() {
    Base* b = new Derived();
    // 尝试进行动态转换,但 Base 不是多态类型
    Derived* d = dynamic_cast<Derived*>(b);  // UB:因为 Base 没有虚函数
    if (d) {
        std::cout << "Converted successfully." << std::endl;
    } else {
        std::cout << "Conversion failed." << std::endl;
    }
    delete b;
    return 0;
}

3. const_cast(去除 const/volatile 限定符)

3.1 正确用法:修改可变数据

如果对象本身不是 const,通过 const_cast 去除指针的 const 属性。

#include <iostream>
void modify(const char* str) {
    // 修改非 const 字符数组是安全的
    char* p = const_cast<char*>(str);
    p[0] = 'H';
}

int main() {
    char str[] = "hello";
    modify(str);
    std::cout << "Modified string: " << str << std::endl;  // 输出:Hello
    return 0;
}

3.2 UB 案例:修改真正的 const 对象

如果对象本身是 const,再通过 const_cast 修改会导致 UB。

#include <iostream>
int main() {
    const int a = 10;
    // a 本身是 const,将其地址转换为 int* 后修改是未定义行为
    int* p = const_cast<int*>(&a);
    *p = 20;  // UB:尝试修改只读数据
    std::cout << "a = " << a << std::endl;
    return 0;
}

4. reinterpret_cast(重解释转换)

4.1 正确用法:指针与整数之间转换

#include <iostream>
#include <cstdint>
int main() {
    int a = 42;
    // 将指针转换为整数
    uintptr_t addr = reinterpret_cast<uintptr_t>(&a);
    // 再转换回指针
    int* p = reinterpret_cast<int*>(addr);
    std::cout << "*p = " << *p << std::endl;  // 输出:42
    return 0;
}

4.2 UB 案例:错误地将不同类型的指针相互转换

如果将一个类型的指针错误地解释为另一个不兼容类型,会导致 UB。

#include <iostream>
int main() {
    int a = 10;
    // 错误地将 int* 转换为 double*
    double* p = reinterpret_cast<double*>(&a);
    // 尝试以 double* 方式访问内存,可能破坏内存布局,导致 UB
    std::cout << "*p = " << *p << std::endl;  // UB
    return 0;
}

5. C 风格转换((T)value)

5.1 案例:C 风格转换的混合行为

C 风格转换可能同时应用了 static_cast、const_cast 和 reinterpret_cast,容易引入隐患,不推荐使用。

#include <iostream>
class Base {};
class Derived : public Base {};

int main() {
    Base b;
    // C 风格转换将 b 强制转换为 Derived*,相当于 static_cast 和 reinterpret_cast 的混合,
    // 没有运行时检查,可能导致 UB
    Derived* d = (Derived*)&b;  // UB
    return 0;
}

视频链接:

 关注微信公众号 程序员陈子青 解锁你的高薪offer之旅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员陈子青

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

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

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

打赏作者

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

抵扣说明:

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

余额充值