显式转换:显式将对象转换为另一种类型。
与命名的强制类型转换相比,旧式的强制类型转换从表现形式上来说不那么清晰明了,容易被看漏,所以一旦转换过程出现问题,追踪起来也更加困难。
C++ 引入新的强制类型转换机制,主要是为了克服C语言强制类型转换的以下三个缺点:
- 没有从形式上体现转换功能和风险的不同。
例如,将 int 强制转换成 double 是没有风险的,而将常量指针转换成非常量指针,将基类指针转换成派生类指针都是高风险的,而且后两者带来的风险不同(即可能引发不同种类的错误),C语言的强制类型转换形式对这些不同并不加以区分。
-
将多态基类指针转换成派生类指针时不检查安全性,即无法判断转换后的指针是否确实指向一个派生类对象。
-
难以在程序中寻找到底什么地方进行了强制类型转换。
一、static_cast
- 将较大的算术类型转换为较小的算术类型
double slope = static_cast<double>(j)/i;
相当于 (double)j/i
#include <iostream>
using namespace std;
class A
{
public:
operator int() { return 1; }
operator char*() { return NULL; }
};
int main()
{
A a;
int n;
char* p = "New Dragon Inn";
n = static_cast <int> (3.14); // n 的值变为 3
n = static_cast <int> (a); //调用 a.operator int,n 的值变为 1
p = static_cast <char*> (a); //调用 a.operator char*,p 的值变为 NULL
n = static_cast <int> (p); //编译错误,static_cast不能将指针转换成整型
p = static_cast <char*> (n); //编译错误,static_cast 不能将整型转换成指针
return 0;
}
一般来说,如果编译器发现一个较大的算术类型试图赋值给较小的类型,就会给出警告信息;但是当我们执行了显式的类型转换后,警告信息就会被关闭了。
-
将非const转换为const。
-
static_cast对于编译器无法自动执行的类型转换也非常有用。例如,我们可以使用static_cast找回存在于void*指针中的值。
void* p = &d; //任何非常量对象的地址都能存入void*
double* dp = static_cast<double*>(p);
- static_cast 不能用于在不同类型的指针之间(如char*与int*之间)互相转换,也不能用于整型和指针之间的互相转换,当然也不能用于不同类型的引用之间的转换。因为这些属于风险比较高的转换。
二、dynamic_cast
适用于以下情况:我们想使用基类对象的指针或引用执行某个派生类操作并且该操作不是虚函数。
- RTTI:
实现运行时类型识别。运行时类型识别(run-time type identification,RTTI)的功能由两个运算符实现:
- typeid运算符,用于返回表达式的类型。
- dynamic_cast运算符,用于将基类的指针或引用安全地转换成派生类的指针或引用。
-
dynamic_cast 用于在类的继承层次之间进行类型转换,它既允许向上转型(Upcasting),也允许向下转型(Downcasting)。 ** 可用于将基类的指针或引用安全地转换成派生类的指针或引用**。
-
有三种使用形式:
type通常应该是一个类类型,通常情况下应该含有虚函数。
e的类型必须符合以下三个条件中的任意一个:e的类型是目标type的公有派生类、e的类型是目标type的公有基类或者e的类型就是目标type的类型。如果符合,则类型转换可以成功。否则,转换失败。
- dynamic_cast<type*>(e) //e必须是一个有效的指针;
- dynamic_cast<type&>(e) //e必须是一个左值;
- dynamic_cast<type&&>(e) //e不能是左值;
三、const_cast
-
将常量对象转换为非常量对象的行为:cast away the const. 实现有时需要对const对象进行修改。
-
const_cast 比较好理解,它用来去掉表达式的 const 修饰或 volatile 修饰。换句话说,const_cast 就是用来将 const/volatile 类型转换为非 const/volatile 类型。只有const_cast可以改变常量表达式的常量属性。
-
只能改变运算对象底层const。
-
将 const 引用转换为同类型的非 const 引用,将 const 指针转换为同类型的非 const 指针时可以使用 const_cast 运算符。
#include <iostream>
using namespace std;
int main(void) {
int d = 2;
const int* a = &d;
int* b = const_cast<int*>(a);
cout<<*a<<endl;
cout<<*b<<endl;
*b = 3;
cout<<*a<<endl;
cout<<*b<<endl;
return 0;
}
输出:
2
2
3
3
- 但是:
#include <iostream>
using namespace std;
int main(void) {
const int d = 2;
int* a = const_cast<int*>(&d);
*a = 3;
cout<<d<<endl;
return 0;
}
输出为:
2
这是因为使用变量d的语句在编译期就被替换为了2。
四、 reinterpret_cast
- reinterpret_cast是对运算对象的二进制位的重新解释。
int* ip;
char* pc = reinterpret_cast<char*>(ip);
我们必须牢记pc所指的真实对象是一个int而非字符,如果把pc当成普通的字符指针使用就可能在运行时发生错误。
- reinterpret_cast本质上依赖于机器。要想安全地使用reinterpret_cast必须对涉及的类型和编译器实现转换的过程都非常了解。