关键字 | 说明 |
---|---|
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; }