cast-name<type>(expression);
cast-name : static_cast 、dynamic_cast 、 const_cast 、 reinterpret_cast。
dynamic_cast
支持运行时的类型识别。
static_cast
任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。
当需要把一个较大的算术类型赋值给较小的类型时,static_cast非常有用。
对于编译器无法自动执行的类型转换也非常有用。例如:
- 我们可以使用static_cast找回存在于void *指针中的值:
void * p = &d; //任何非常量对象都能存入void*
double *dp =static_cast<double*> (p); //必须确保转换后所得类型就是指针所指类型,不然,未定义。
const_cast
用于改变运算对象的底层const。
const_cast转换符是用来移除变量的const或volatile限定符。
const char *cp;
char * p=const_cast<char*> (cp); //正确,但通过cp写值是未定义行为
传统转换方式实现const_cast。const_cast实现原因就在于C++对于指针的转换是任意的,它不会检查类型,任何指针之间都可以进行互相转换,因此const_cast就可以直接使用显示转换(int*)来代替:
const int constant =21;
const int * const_p=& constant;
int *modifier=(int *)(const_p);
或者可以写作:
const int constant =21;
int *modifier =(int*)(&constant);
但是, 上面只改变了const_p所指向内容的值,不能改变constant的值,虽然它们指向了同一个地址。
实际上,通过改变*modifier的值来改变cons值是未定义的行为,我们需要尽量避免未定义行为的出现。
那么问题来了,既然不想修改const变量的值,为什么要去const呢?
原因是,我们可能调用了一个参数不是const的函数,而我们要传进去的实际参数确是const的,但是我们知道这个函数是不会对参数做修改的。于是我们就需要使用const_cast去除const限定,以便函数能够接受这个实际参数。
#include<iostream>
using namespace std;
void printer(int *val, string seperator ="\n")
{
cout<<val<<seperator;
}
int main(void)
{
const int constant =20;
printer(const_cast<int *>(&constant));
return 0;
}
出现这种情况的原因,可能是我们所调用的方法是别人写的。
还有一种我能想到的原因,是出现在const对象想调用自身的非const方法的时候,因为在类定义中,const也可以作为函数重载的一个标识符。
实际上,const_cast常用于有函数重载的上下文中1。
reinterpret_cast
reinterpret_cast通常为运算对象的位模式提供较低层次上的解释。
int *ic;
char *pc =reinterpret_cast<char *>(ip);
必须时刻牢记pc所指向的真实对象是一个int而不是字符,如果把pc当成普通的字符指针就可能在运行时发生错误。
string str(pc); //导致异常
使用reinterpret_cast是非常危险的,其本质上依赖于机器,想要安全地使用它,必须对涉及的类型和编译器实现转换的过程非常了解。
要避免强制类型的转换。
旧式的强制类型转换
type(expr);
(type)expr;
根据涉及的类型不同,旧式的强制类型转换分别具有与const_cast 、static_cast、 reinterpret_cast相似的行为。
当我们在某处执行旧式的强制类型转换,如果换成const_cast 、static_cast也合法,则其行为与对应的命名转换一致。如果替换后不合法,则其执行与 reinterpret_cast类似的功能:
char *pc =(char *)ip; //ip是指向整数的指针
与 reinterpret_cast一样。
const_cast与函数重载:
const string &shorterString (const string &s1,const string &s2) { return s1.size()<s2.size() ? s1:s2;}
这个函数的参数和返回类型都是const string的引用,如果对两个非常量实参调用这个函数是可行的,但其返回值仍是const string的引用。
因此,我们需要一个新的shorterString函数,当他的实参不是常量时,得到的结果是一个普通的引用,使用const_cast:
string &shorterString (string &s1, string &s2) { auto &r = shorterString (const_cast <const string &>(s1) ,const_cast <const string&>(s2)) ; return const_cast <string&> (r); }
↩︎