C++类型转换运算符

关键字 说明
static_cast 用于良性转换,一般不会导致意外发生,风险很低。
const_cast 用于 const 与非 const、volatile 与非 volatile 之间的转换。
reinterpret_cast 高度危险的转换,这种转换仅仅是对二进制位重新解释,是static_cast的互补
dynamic_cast 借助 RTTI,用于类型安全的下行转换。上行转换与static_cast一样。

 

static_cast关键字

该运算符可以进行良性类型转换,转换风险较低。它主要有如下几种用途:   ①用于基类(父类)和派生类(子类)之间指针或引用的转换。     进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;     进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。   ②用于基本数据类型之间的转换,例如 short 转 int、int 转 double、int转换成char等,这种转换的安全性也要开发人员来保证。   ③把空指针转换成目标类型的空指针,例如 void * 转 int *。   ④把任何类型的表达式转换成void类型, 例如 int 转 void。   ⑤无法将const、volatile、__unaligned属性去掉

static_cast 没有类型检查来保证转换的安全性,不能用于无关类型之间的转换,例如:

  • 两个具体类型指针之间的转换,如 int * 转 double *、 Student * 转 int * 等。不同类型的数据存储格式不一样,长度也不一样。用 A 类型的指针指向 B 类型的数据后,会按照 A 类型的方式来处理数据:如果是读取操作,可能会得到一堆没有意义的值;如果是写入操作,可能会使 B 类型的数据遭到破坏;当再次以 B 类型的方式读取数据时会得到一堆没有意义的值。
  • int 和指针之间的转换。将一个具体的地址赋值给指针变量是非常危险的,因为该地址上的内存可能没有分配,也可能没有读写权限。

static_cast 是在编译期间转换,转换失败的话会抛出一个编译错误。

    int m = 100;long n = static_cast<long>(m);  //宽转换,没有信息丢失
    char ch = static_cast<char>(m);  //窄转换,可能会丢失信息
    int *p1 = static_cast<int*>(malloc(10 * sizeof(int)));  //将void指针转换为具体类型指针
    void *p2 = static_cast<void*>(p1);  //将具体类型指针,转换为void指针
   
    //下面的用法是错误的
    float *p3 = static_cast<float*>(p1);  //不能在两个具体类型的指针之间进行转换
    p3 = static_cast<float*>(0X2DF9);  //不能将整数转换为指针类型

 

const_cast 关键字

 const_cast 就是用来将 const/volatile 类型转换为非 const/volatile 类型。

    const int n = 100;
    int *p = const_cast<int*>(&n);
    *p = 234;
    cout << " n = " << n << endl; //100
    cout << " *p = " << *p << endl; //234

&n用来获取 n 的地址,它的类型为const int *,必须使用 const_cast 转换为int *类型后才能赋值给 p。由于 p 指向了 n,并且 n 占用的是栈内存,有写入权限,所以可以通过 p 修改 n 的值。

由于 C++ 对常量的处理更像是编译时期的#define,是一个值替换的过程,代码中所有使用 n 的地方在编译期间就被替换成了 100。换句话说,第 4 行代码被修改成了下面的形式:

    cout << " n = " << 100 << endl; //100

 

reinterpret_cast 关键字

reinterpret_cast 仅仅是对二进制位重新解释,不会借助已有的转换规则对数据进行调整。

reinterpret_cast 可以认为是 static_cast 的一种补充,一些 static_cast 不能完成的转换,就可以用 reinterpret_cast 来完成,例如两个具体类型指针之间的转换、int 和指针之间的转换。

    //将 char* 转换为 float*
    char str[] = "http://c.biancheng.net";
    float *p1 = reinterpret_cast<float*>(str);
    cout << *p1 << endl; //3.0262e+29

    //将 int 转换为 int*
    int *p = reinterpret_cast<int*>(100);
    cout << *p << endl; //100

 

dynamic_cast 关键字

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

  • 上行转换是无条件的,只要待转换的两个类型之间存在继承关系,并且基类包含了虚函数(这些信息在编译期间就能确定),不会进行任何检测,一定能成功。
  • 下行转换的前提必须是安全的,要借助 RTTI 进行检测,所有只有一部分能成功。
  • dynamic_cast 只能转换指针->指针或引用->引用。对于指针,如果转换失败将返回 NULL;对于引用,如果转换失败将抛出std::base_cast异常。

dynamic_cast 与 static_cast 是相对的。dynamic_cast 会在程序运行期间借助 RTTI 进行类型转换,这就要求基类必须包含虚函数;static_cast 在编译期间完成类型转换,能够更加及时地发现错误。

//下行转换

class A {
public:
    virtual void func() const { cout<<"Class A"<<endl; }
private:
    int m_a;
};

class B : public A {
public:
    virtual void func() const { cout<<"Class B"<<endl; }
private:
    int m_b;
};

class C : public B {
public:
    virtual void func() const { cout<<"Class C"<<endl; }
private:
    int m_c;
};

class D : public C {
public:
    virtual void func() const { cout<<"Class D"<<endl; }
private:
    int m_d;
};

int main(){
    A *pa = new A();
    B *pb;
    C *pc;
   
    //情况①
    pb = dynamic_cast<B*>(pa);  //向下转型失败
    pc = dynamic_cast<C*>(pa);  //向下转型失败
   
    //情况②
    pa = new D();  //向上转型都是允许的
    pb = dynamic_cast<B*>(pa);  //向下转型成功
    pc = dynamic_cast<C*>(pa);  //向下转型成功

    return 0;
}

 

上一篇:C++ 关键字


下一篇:log4j2不打印日志或者打印不受控制的日志解决办法