c++ 强制类型转换

前言

在c语言中学的强制转换是用()来实现的; 而在c++中更多的是用case-name系列的关键字来告诉编译器我们需要转换的类型. c++引入这些关键字也是为了看代码的时候清晰明了, 每个关键字都有指定的功能. 下面我们就来分析这些关键字.

case-name关键字

1. static_cast

在编译期间完成类型转换.

a. 将原有的自动类型转换 , 如 : short转为int, int转为double, 非const转为const类型

short sh;
int i = static_cast<int>(sh);
const int ci = static_cast<const int>(i);

b. void 指针和具体类型指针之间的转换

void *vp;
int *ip = static_cast<int*>(vp);

c. 有转换构造函数或者类型转换函数的类与其它类型之间的转换

如 : A是B的基类

B *b;
A *a = static_cast<A *>(b); // 这种建议使用dynamic_cast来转换

不能用于无关类型之间的转换 , 如 : int* 转为double* 等

int *pi;
double *di = static_cast<double *>(pi); // error

2. const_cast

const_cast (常用于函数的重载) 常量指针(引用)被转化成非常量指针(引用),并且仍然指向原来的对象

顾名思义, const_cast就是在我们需要修改const修饰的常量的时候用.

const int ci = 1;
int *p = const_cast<int*>(&ci);
*p = 10;

cout << &ci << " " << p << endl;    // 0x7ffd856729cc 0x7ffd856729cc
cout << ci << endl; // 1
cout << *p << endl; // 10

注意 : 上面的ci的值最终还是没有被修改, 这就是后半句 : 仍然指向原来的对象. 我们只能通过const_cast忽略对象的属性, 却依然不能修改对象.

可能有人就认为const_cast并没有用, 但是我们确实用int*指向了const int*了, 这是一般我们都无法做到的. 同样, 下面还有const_cast能够做到的.

这有一部分的代码, 我们在重载const函数时, 常常会重复写很多一样的代码, 而使用const_cast就可以避免写重复的代码.

class A
{
public:
    ...
    const type& operator[](std::size_t size) const
    {
        return *(ar + size);
    }
    type& operator[](std::size_t size)
    {
        return const_cast<type &>(static_cast<const A&>(*this)[size]);
    }

private:
    ...
    std::size_t size;
    type * ar;
};

3. reinterpret_cast

reinterpret_cast这种转换仅仅是对二进制位的重新解释(修改), 不会借助已有的转换规则对数据进行调整, 非常简单粗暴, 风险很高, 一般我们不推荐使用.

但是既然c++规定了这中转换, 那么什么时候用合适?在IBM C++指南中明确说了

  • 从指针类型到一个足够大的整数类型
  • 从整数类型或者枚举类型到指针类型
  • 从一个指向函数的指针到另一个不同类型的指向函数的指针
  • 从一个指向对象的指针到另一个不同类型的指向对象的指针
  • 从一个指向类函数成员的指针到另一个指向不同类型的函数成员的指针
  • 从一个指向类数据成员的指针到另一个指向不同类型的数据成员的指针

总结来说:reinterpret_cast用在任意指针(或引用)类型之间的转换;以及指针与足够大的整数类型之间的转换;从整数类型(包括枚举类型)到指针类型,无视大小

就像下面这样static_cast无法做的但reinterpret_cast就可以完成, 但是赋值等操作却会运行时报错, 这就是reinterpret_cast不安全之处, 它能让代码通过编译, 操作时却会报错, 一般建议reinterpret_cast只有将转换后的类型值转换回到其原始类型来使用, 做一个中间临时转存。

int *pi = NULL;
double *di = reinterpret_cast<double *>(pi);

4. dynamic_cast

dynamic_cast用于在类的继承层次之间进行类型转换, 它既允许向上转型, 也允许向下转型.

class A {};
class B : public A {};

向上转型 : 基类指针(引用)指向子类指针(引用), 这样的转换是安全的.

B *b;
A *a = static_cast<A *>(b); 
A *ta = dynamic_cast<A *>(b);// 也可写成这样, 最好建议这样转换

向下转型 : 借助 RTTI 信息进行检测, 确定安全的才能转换成功, 否则就转换失败, 有风险.

A *a;
B *b = dynamic_cast<B *>(a);

总结

虽然c语言的()强制能用, 但是最好推荐使用c++的转化系列, 毕竟看代码的时候很容易能够知道转化对象和原因, 也容易分析. 本片我将四种转化尽量写的简单, 多用实例证明, 只是希望能够快速的明了每个的用法.

  1. static_cast : 有关联的 对象之间能够进行转化.
  2. const_cast : 忽略const/volatile修饰, 但是实际不会修改对象, 常用于重载
  3. dynamic_cast : 最多用于向下转化, 但并不安全
  4. reinterpret_cast : 二进制间, 可无关联对象间的转化, 非常不安全.
posted @ 2019-01-29 21:08 倔强的铃铛 阅读(...) 评论(...) 编辑 收藏