由于C语言提供了强大的类型转化,显示转化和隐身转化,并且强大的强制转化,基本已经做够用了,所以很少能用到C++提供的这四个类型转换的关键字。今天就来探讨一下这四个关键字了。
下面是这四类显示转换的关键字:
static_cast: 用于良性转换(一般的转换,包括自动转换),转换的时候甚至可以不用这个关键字;
const_cast: 用于const/volatile与非const/volatile之间的转换;
reinterpret_cast: 高度危险的重翻译转换,但可以实现最灵活的类型转换;
dynamic_cast: 用于类型安全的向下转换。
①用于类层次结构中基类和子类之间指针或引用的转换。
进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换。如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
int num1=50; int a[20];
long num2 = static_cast<long>(num1); // 宽化转换,没有信息丢失
char num3 = static_cast<char>(num3); // 窄化转换,有信息丢失,具体转换规则请参考相关教程
void* p = static_cast<void*>(a); // 使用void*的强制变换,允许
float* q = static_cast<float*>(p); // 使用void*的强制变换,允许
// float* r = static_cast<float*>(a); // 错误,没有经过void*的强制指针类型变换,不允许
const_cast的主要作用:
这个转换类型操纵传递对象的const属性,或者是设置或者是移除:
const int a = 50; volatile int b = 100;
int* p = const_cast<int*>(&a); *p = 51;
cout << "a=" << a << endl; // 正确的输出a应该没有变动,a=50
cout << "*p=" << *p <<endl; // 但是神奇的是 *p=51,内存已经变了,但是不会刷新到const a上面
int* q = const_cast<int*>(&b); *q = 101;
cout << "b=" << b << endl; // 用volatile的话,随时刷新,因此输出b=101,已经改变
cout << "*q=" << *q << endl; // 这时候*q自然也是*q=101
reinterpret_cast的主要作用:
转换一个指针为其它类型的指针。它也允许从一个指针转换为整数类型。反之亦然。(译注:是指针具体的地址值作为整数值?)
这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。
如果情况是从一个指针到整型的拷贝,内容的解释是系统相关的,所以任何的实现都不是方便的。一个转换到足够大的整型能够包含它的指针是能够转换回有效的指针的。
代码:
class A {};
class B {};
A * a = new A;
B * b = reinterpret_cast<B *>(a);
'reinterpret_cast'就像传统的类型转换一样对待所有指针的类型转换。
dynamic_cast的主要作用:
只用于对象的指针和引用。当用于多态类型时,它允许任意的隐式类型转换以及相反过程。不过,与static_cast不同,在后一种情况里(注:即隐式转换的相反过程),dynamic_cast会检查操作是否有效。也就是说,它会检查转换是否会返回一个被请求的有效的完整对象。
检测在运行时进行。如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL.
代码:
class Base { virtual dummy() {} };
class Derived : public Base {};
Base* b1 = new Derived;
Base* b2 = new Base;
Derived* d1 = dynamic_cast<Derived*>(b1); //succeeds
Derived* d2 = dynamic_cast<Derived*>(b2); //fails: returns 'NULL'
如果一个引用类型执行了类型转换并且这个转换是不可能的,一个bad_cast的异常类型被抛出:
代码:
class Base { virtual dummy() {} };
class Derived : public Base { };
Base* b1 = new Derived;
Base* b2 = new Base;
Derived d1 = dynamic_cast<Derived&*>(b1); //succeeds
Derived d2 = dynamic_cast<Derived&*>(b2); //fails: exception thrown