static_cast, dynamic_cast, const_cast, reinterpret_cast和C风格转换(如(int)x)的用法详解

一、static_cast

static_cast 是 C++ 中的一个类型转换操作符,用于执行编译时的静态类型转换,类似于C风格转换(如(int)x)。但是比C风格转换更安全。它主要用于较为明确的类型转换,例如数值类型之间的转换,基本数据类型的指针和引用之间的转换。
当转换对象具有继承关系时,最好不要用static_cast,因为它不会做运行时类型检查。

int main() {
    double d = 3.14;
    int i = static_cast<int>(d);  // 将double类型的d转换为int类型
    
    return 0;
}

除此之外,static_cast也可以用于将数值、指针或引用从非const转换为const。这点和const_cast功能相反。如下:

#include <iostream>

void printValue(const int& value) {
    std::cout << "Value: " << value << std::endl;
}

int main() {
    int number = 10;
    printValue(static_cast<const int&>(number));  // 将非 const 整数值转换为 const 引用,但其实不加static_cast也能通过编译

    int value = 10;
    const int* ptr = static_cast<const int*>(&value); // 将int类型的指针转换为const int类型的指针,但其实不加static_cast也能通过编译

    // 此时ptr指向的对象是不可修改的,这样可以确保value不会在ptr的作用域内被修改
    // *ptr = 20; // 这个会导致编译错误

    return 0;
}

加了static_cast是显式转换。但其实不加static_cast也能通过编译,编译器会自动做隐式转换。

二、dynamic_cast

如果使用 dynamic_cast 将指向基类对象的指针转换为指向派生类对象的指针,而转换不安全,dynamic_cast 会返回空指针。但是如果用static_cast,则会显示都成功。所以在涉及到父类和子类对象之间的转换时,不要用static_cast,而是dynamic_cast。
以下是一个使用 dynamic_cast 进行向下转换的示例,演示了当转换失败时 dynamic_cast 返回空指针的情况:

#include <iostream>

class Base {
public:
    virtual ~Base() {}
};

class Derived : public Base {
    // 派生类的内容
};

int main() {
    Base base_1;
    
    // 尝试将指向基类对象的指针转换为指向派生类对象的指针
    Derived* derived_1 = dynamic_cast<Derived*>(&base_1); 
    if (derived_1 == nullptr) {
        std::cout << "base_1转换失败" << std::endl;
    } else {
       std::cout << "base_1转换成功" << std::endl;
    }
	
	Base* base_2 = new Derived();
    Derived* derived_2 = dynamic_cast<Derived*>(base_2); 
    if (derived_2 == nullptr) {
        std::cout << "base_2转换失败" << std::endl;
    } else {
       std::cout << "base_2转换成功" << std::endl;
    }

}

输出是:

base_1转换失败
base_2转换成功
main.cpp: In function ‘int main():
main.cpp:16:56: warning: dynamic_cast of ‘Base base_1’ to ‘class Derived*’ can never succeed
   16 |     Derived* derived_1 = dynamic_cast<Derived*>(&base_1);
      |                                  ^

如果用static_cast,则会显示都成功。
但是dynamic_cast无法用于一般类型转换,它不能直接用于数值类型之间的转换等。所以dynamic_cast也无法完全取代static_cast。

三、const_cast

const_cast 主要用于将 const 类型对象的常量属性去除,以便能够对其进行修改。举个例子:

#include <iostream>

class MyClass {
public:
    MyClass(int value) : m_value(value) {}
    
    void modifyValue() const {
        const_cast<int&>(m_value) = 20;  // 去除常量性,允许修改成员变量
    }

    void printValue() const {
        std::cout << "Value: " << m_value << std::endl;
    }

private:
    int m_value;
};

int main() {
    const MyClass obj(10);//注意这里的const,表示对象obj是一个常量对象,只能调用const修饰的函数
    obj.printValue();  // 输出 10

    obj.modifyValue();  // 允许修改常量对象
    obj.printValue();  // 输出 20

    return 0;
}

程序输出是:

Value: 10
Value: 20

四、reinterpret_cast

reinterpret_cast可以用于执行各种不同类型指针之间的转换,甚至是指针类型和整数类型之间的转换。它的主要功能是执行底层的位模式重解释,而不进行标准的类型转换或数值转换。它也不做安全检查。例子如下:

#include <iostream>

int main() {
    int number = 65;
    char* charPtr = reinterpret_cast<char*>(&number);

    std::cout << *charPtr << std::endl;  // 输出 'A',将 int 转换为 char

    return 0;
}

在这个例子中,我们使用 reinterpret_cast 将 int 类型的指针转换为 char 类型的指针,这允许我们将整数65的位模式解释为字符 ‘A’。需要注意的是,这种转换方式是非常危险的,因为 char 类型指针不一定能够准确地解释 int 类型的数据。
尽管它非常危险,但在某些情况下是必需的。比如和C代码进行交互。使用它的场景比较少,真正要用时也需要谨慎,因为它没有安全检查。

五、C风格转换(如(int)x)

它跟static_cast类似,但是static_cast更安全,它会做编译时类型检查。在写C++代码时,建议使用static_cast。
举例说明

#include <iostream>

int main() {
    double d = 10.5;
    int i = static_cast<int>(d); // 将 double 转换为 int,编译成功

    char* ptr = static_cast<char*>(&i); // 将 int* 转换为 char*,编译报错
    //char* ptr = (char*)(&i); // 将 int* 转换为 char*, 编译成功

    return 0;
}

编译结果是:

main.cpp: In function ‘int main():
main.cpp:7:38: error: invalid static_cast from type ‘int*’ to type ‘char*7 |     char* ptr = static_cast<char*>(&i); // 将 int* 转换为 char*,编译报错
      |                             ^
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

码到程攻

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

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

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

打赏作者

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

抵扣说明:

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

余额充值