C++ 强制类型转换 static_cast、dynamic_cast、const_cast、reinterpret_cast

1、static_cast

static_cast < new_type > ( expression )    

**强制转换 可用于强制隐形转换如int转型为double还可以用于很多这样的转换的反向转换 (例如,void指针转型为有类型指针,基类指针转型为派生类指针)但是它不能将一个const对象转型为non-const对象(只有 const_cast能做到)它允许子类类型的指针转换为父类类型的指针(这是一个有效的隐式转换),同时,也能够执行相反动作:转换父类为它的子类。
如下例:

#include <vector>
#include <iostream>

struct B {
    int m = 0;
    void hello() const {
        std::cout << "Hello world, this is B!\n";
    }
};
struct D : B {
    void hello() const {
        std::cout << "Hello world, this is D!\n";
    }
};

enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };

int main()
{
    // 1: 初始化转换
    int n = static_cast<int>(3.14);
    std::cout << "n = " << n << '\n';
    std::vector<int> v = static_cast<std::vector<int>>(10);
    std::cout << "v.size() = " << v.size() << '\n';

    // 2: 静态向下转型
    D d;
    B& br = d; // 通过隐式转换向上转型
    br.hello();
    D& another_d = static_cast<D&>(br); // 向下转型
    another_d.hello();

    // 3: 左值到右值
    std::vector<int> v2 = static_cast<std::vector<int>&&>(v);
    std::cout << "after move, v.size() = " << v.size() << '\n';

    // 4: 弃值表达式
    static_cast<void>(v2.size());

    // 5. 隐式转换的逆
    void* nv = &n;
    int* ni = static_cast<int*>(nv);
    std::cout << "*ni = " << *ni << '\n';

    // 6. 数组到指针后随向上转型
    D a[10];
    B* dp = static_cast<B*>(a);

    // 7. 有作用域枚举到 int 或 float
    E e = E::ONE;
    int one = static_cast<int>(e);
    std::cout << one << '\n';

    // 8. int 到枚举,枚举到另一枚举
    E e2 = static_cast<E>(one);
    EU eu = static_cast<EU>(e2);

    // 9. 指向成员指针向上转型
    int D::*pm = &D::m;
    std::cout << br.*static_cast<int B::*>(pm) << '\n';

    // 10. void* 到任何类型
    void* voidp = &e;
    std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}

运行结果:

n = 3
v.size() = 10
Hello world, this is B!
Hello world, this is D!
after move, v.size() = 0
*ni = 3
1
0

2、dynamic_cast

dynamic_cast < new_type > ( expression )    

new_type - 指向完整类类型的指针、到完整类类型的引用,或指向(可选的 cv 限定) void 的指针
expression - 若 new_type 为引用,则为完整类类型的左值 (C++11 前)泛左值 (C++11 起)表达式,若 new_type 为指针,则为指向完整类类型的指针纯右值。
若转型成功,则 dynamic_cast 返回 new_type 类型的值。
若转型失败且 new_type 是指针类型,则它返回该类型的空指针。若转型失败且 new_type 是引用类型,则它抛出匹配类型 std::bad_cast 处理块的异常。
注意:dynamic_cast在将父类cast到子类时。父类必需要有虚函数。比如在以下的代码中将CBasic类中的test函数不定义成
virtual时,编译器会报错:error C2683: dynamic_cast : “CBasic”不是多态类型

如下例:

#include <iostream>
using namespace std;

class CBasic
{
public:
    virtual int test(){return 0;} // 一定要是 virtual
};

class CDerived : public CBasic
{
public:
    virtual int test(){    return 1;}
};

int main()
{
    CBasic        cBasic;
    CDerived    cDerived;

    CBasic * pB1 = new CBasic;
    CBasic * pB2 = new CDerived;

    //dynamic cast failed, so pD1 is null.
    CDerived * pD1 = dynamic_cast<CDerived * > (pB1);
    std::cout << "pD1 = " << pD1 << std::endl;

    //dynamic cast succeeded, so pD2 points to  CDerived object
    CDerived * pD2 = dynamic_cast<CDerived * > (pB2);
    std::cout << "pD2 = " << pD2 << std::endl;

    //dynamci cast failed, so throw an exception.
    //    CDerived & rD1 = dynamic_cast<CDerived &> (*pB1);

    //dynamic cast succeeded, so rD2 references to CDerived object.
    CDerived & rD2 = dynamic_cast<CDerived &> (*pB2);

    return 0;
}

3、const_cast
const_cast一般用于强制消除对象的常量性。它是唯一能做到这一点的C++风格的强制转型。这个转换能剥离一个对象的const属性,也就是说允许你对常量进行修改。

const_cast < new_type > ( expression )      

如下例:

#include <iostream>

struct type {
    int i;

    type(): i(3) {}

    void f(int v) const
    {
        // this->i = v;                 // 编译错误: this 是指向 const 的指针
        const_cast<type*>(this)->i = v; // 只要该对象不是 const 就 OK
    }
};

class C
{

};

int main()
{
    int i = 3;                 // 不声明 i 为 const
    const int& rci = i;
    const_cast<int&>(rci) = 4; // OK :修改 i
    std::cout << "i = " << i << '\n';

    type t; // 假如这是 const type t ,则 t.f(4) 会是未定义行为
    t.f(4);
    std::cout << "type::i = " << t.i << '\n';

    const int j = 3; // 声明 j 为 const
    int* pj = const_cast<int*>(&j);
    // *pj = 4;      // 未定义行为

    void (type::* pmf)(int) const = &type::f; // 指向成员函数的指针
    // const_cast<void(type::*)(int)>(pmf);   // 编译错误: const_cast 不在成员函数指针上工作


    const C *a = new C;
    C *b = const_cast<C *>(a);
}

运行结果:

i = 4
type::i = 4

4、reinterpret_cast

reinterpret_cast < new_type > ( expression )        

reinterpret_cast 是特意用于底层的强制转型,导致实现依赖(就是说,不可移植)的结果,例如,将一个指针转型为一个整数。这样的强制类型在底层代码以外应该极为罕见。操作 结果只是简单的从一个指针到别的指针的值得二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。

如下例:

#include <cstdint>
#include <cassert>
#include <iostream>
int f() { return 42; }
int main()
{
    int i = 7;

    // 指针到整数并转回
    std::uintptr_t v1 = reinterpret_cast<std::uintptr_t>(&i); // static_cast 为错误
    std::cout << "The value of &i is 0x" << std::hex << v1 << '\n';
    int* p1 = reinterpret_cast<int*>(v1);
    assert(p1 == &i);

    // 到另一函数指针并转回
    void(*fp1)() = reinterpret_cast<void(*)()>(f);
    // fp1(); 未定义行为
    int(*fp2)() = reinterpret_cast<int(*)()>(fp1);
    std::cout << std::dec << fp2() << '\n'; // 安全

    // 通过指针的类型别名使用
    char* p2 = reinterpret_cast<char*>(&i);
    if(p2[0] == '\x7')
        std::cout << "This system is little-endian\n";
    else
        std::cout << "This system is big-endian\n";

    // 通过引用的类型别名使用
    reinterpret_cast<unsigned int&>(i) = 42;
    std::cout << i << '\n';

    const int &const_iref = i;
    // int &iref = reinterpret_cast<int&>(const_iref); // 编译错误——不能去除 const
    // 必须用 const_cast 代替: int &iref = const_cast<int&>(const_iref);
}

运行结果:

The value of &i is 0x61fe84
42
This system is little-endian
42

dynamic_cast和static_cast的区别

在C++中,dynamic_cast和static_cast都是用来转型的操作符,两者不合理的运用可能会导致在编译期合法的类型转换操作却在运行期也会引发错误,当转型操作涉及到对象指针或引用时,更易发生错误。 这两者又有什么区别呢?

dynamic_cast操作符会在运行期对可疑的转型操作进行安全检查,而static_cast操作符不会进行安全检查;
dynamic_cast仅对多态有效(转型的源类型必须是多态,但与转型的目标类型是否多态无关),而static_cast可施加与任何类型;
从派生类到基类的 dynamic_cast 可以进行,这称为向上转型;
从基类到派生类的 dynamic_cast 不能进行,称为向下转型;
有继承关系,派生类可通过dynamic_cast向基类转换;
没有继承关系,不能通过dynamic_cast互换;
使用方式:

dynamic_cast<T*>ptr、static_cast<T*>ptr;
dynamic_cast<T&>p、static_cast<T*>p;
1
2
下面用一些简单的代码来说明关于转型的一些知识点:
一个基类指针不经过明确的转型操作,就能指向基类对象或派生类对象;反过来,一个派生类指针指向基类对象是一种不明智的做法。

class B
{

};

部分参考原文链接:https://blog.csdn.net/muyuyuzhong/article/details/82699374`

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值