C++中的四种强制类型转换

C++的类型转换有四种,以支持不同的需求,下面我们一起学习。

1.static_cast转换

① 基本语法:static_cast<type-id>expression

② 使用场景

a.用于类层次结构中基类和派生类之间指针或引用的转换

上行转换(派生类->基类)是安全的

下行转换(基类->派生类)由于没有动态类型检查,是不安全的

b.用于基本数据类型之间的转换,如把int转换为long,这种带来的安全性问题由程序员保证

c.把空指针转换为目标类型的指针

d.把任何类型的表达式转为void类型

③ 使用特点

a.主要执行非多态的转换操作,用于代替C中通常的转换操作

b.隐式转换都建议使用static_cast进行标明和替换

2.dynamic_cast

① 基本用法:dynamic_cast<type-id>expression

② 使用场景:只有在派生类之间转换时才使用dynamic_cast,type-id必须是类指针、类引用或者void*。

③ 使用特点

a.基类必须要有虚函数,因为dynamic_cast是运行时类型检查,需要运行时类型信息,而这个信息是存储在类的虚函数表中,只有一个类定义了虚函数,才会有虚函数表(如果一个类没有虚函数,那么一般意义上,这个类的设计者也不想它成为一个基类)。

b.对于下行转换,dynamic_cast是安全的(当类型不一致时,转换过来的是空指针),而static_cast是不安全的(当类型不一致时,转换过来的是错误意义的指针,可能造成踩内存,非法访问等各种问题)

c.dynamic_cast还可以进行交叉转换

3.const_cast转换

① 基本用法:const_cast<type-id>expression

② 使用场景:

a.常量指针转换为非常量指针,并且仍然指向原来的对象

b.常量引用被转换为非常量引用,并且仍然指向原来的对象

③ 使用特点:

a.cosnt_cast是四种类型转换符中唯一可以对常量进行操作的转换符

b.去除常量性是一个危险的动作,尽量避免使用。一个特定的场景是:类通过const提供重载时,一般都是非常量函数调用const_cast<const T>将参数转换为常量,然后调用常量函数,然后得到结果再调用const_cast <T>去除常量性。

4.reinterpret_cast转换

① 基本用法:reinterpret_cast<type-id>expression

② 使用场景:不到万不得已,不用使用这个转换符,高危操作

③ 使用特点:  

a.interpret_cast是从底层对数据进行重新解释,依赖具体的平台,可移植性差

b.reinterpret_cast可以将整型转换为指针,也可以把指针转换为数组

c.reinterpret_cast可以在指针和引用里进行肆无忌惮的转换

5.比较

① static_cast和dynamic_cast

class Base
{
    public:
        Base(int c = 2):_c(c){}
    public:
        int _c;
};
class Derived:public Base
{
    public:
        int _d;
        int _e;
};
int main(void)
{
    int tempA = 2;
    int tempB = 3;
    Base base;
    
    /*1.无编译告警,但是危险操作,譬如说调用drvPtrA->_d会造成不可预知的后果*/
    Derived *drvPtrA = static_cast<Derived *>(&base);
    
    drvPtrA->_d = 4;
    drvPtrA->_e = 5;
    /*2.输出:tempA为5,tempB为4,踩内存了(机器信息:32位ubuntu,编译器clang++)*/
    cout<<tempA<<endl;
    cout<<tempB<<endl;
    
    /*3.Base中没有虚函数,无法查看运行时信息,编译不过*/
    Derived *drvPtrB = dynamic_cast<Derived *>(base);

    return 0;
}

       在基类派生类互相转换时,虽然static_cast是在编译期完成,效率更高,但是不安全,上例中就示范了一个踩内存的例子。相比之下因为dynamic_cast可以查看运行时信息,上例如果Base含有虚函数,那么drvPtrB就是一个空指针(这可比踩内存什么的好多了),不能操作Derived中_d的数据从而保证安全性,所以应该优先使用dynamic_cast。

② static_cast和reinterpret_cast

class BaseA
{
    public:
        BaseA(int c = 2):_c(c){}
        int _c;
};
class BaseB
{
    public:
        BaseB(int d = 3):_d(d){}
        int _d;
};
int main(void)
{
    BaseA baseA;
    /*1.编译不过*/
    BaseB *baseB = static_cast<BaseB *>(&baseA);
    /*2.无任何编译告警,编译通过,正常运行*/
    BaseB *baseC = reinterpret_cast<BaseB *>(&baseA);
    cout<<baseC->_d<<endl;

    return 0;
}

 static_cast虽然也不是一种绝对安全的转换,但是它在转换时,还是会进行必要的检测(诸如指针越界计算,类型检查)。reinterpret_cast完全是肆无忌惮,直接从二进制开始重新映射解释,是极度不安全的,再次提醒,不到万不得已,不要使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值