隐式转换是编译器替我们完成的:
double a=3.14;
int val=a; //val的值为3
显示转换或称强制类型转换,是我们告诉编译器:你别管我,我就是要这么转换。
格式为:
cast-name<target type>(expression)
cast-name有这四种:static_cast、dynamic_cast、const_cast、reinterpret_cast
- static_cast
任何具有明确定义的类型转换,只要不包含底层const,都能使用static_cast。
1. 当需要把一个较大的算数类型(如double)赋值给较小的类型(如int)时有用:
double a=3.14;
int val=static_cast<int>(a);
如果我们不用static_cast,编译器会警告潜在的精度损失,现在我们告诉它:I don't care,编译器就不会警告了。
2. 对于编译器无法自动执行的类型转换也有用:
double d=3.14;
void *p=&d;
//正确:将void*转换回初始的指针类型
double *dp=static_cast<double*>(p);
- dynamic_cast
当我们想要使用基类对象的指针或引用来调用它的某个派生类的函数,而这个函数正好不是虚函数时,dynamic_cast就派上用场了。一般来说,应该尽可能使用虚函数,这样编译器将根据对象的动态类型自动选择正确的函数版本。但是,并非任何时候都能定义一个虚函数。
dynamic_cast的三种使用形式:
dynamic_cast<target type*>(e);//e必须是个有效的指针
dynamic_cast<target type&>(e);//e必须是个左值
dynamic_cast<target type&&>(e);//e不能是左值
注意:
-
- target type必须是个类类型,且通常情况下该类型应含有虚函数。
- 上面所有形式中,e必须满足以下三个条件中任一个:
- e的类型是target type的公有派生类;
- e的类型是target type的公有基类;
- e的类型就是target type的类型。
- 如果转换目标是指针类型且转换失败,结果为0。
- 如果转换目标是引用类型且转换失败,结果是抛出一个bad_cast异常。
一个指针类型的例子
if(Derived *dp=dynamic_cast<Derived*>(bp))
{
//……
}
else
{
//……
}
Tips:在条件部分执行dynamic_cast操作可以确保
类型转换和
结果检查在同一条表达式中完成。
一个引用类型的例子
void fun(const Base &b)
{
try{
const Derived &d=dynamic_cast<const Derived&>(b);
}catch(bad_cast){
//……
}
}
- const_cast
const_cast的主要作用是修改指针或引用的指向的const属性(去掉const或加上const):
- 将const type*转换为type*
- 将const type&转换为type&。
- 将type*转换为const type*
- 将type&转换为const type&。
const char a='o';
const char *pc=&a;
char *p=const_cast<char*>(pc);
const_cast<string>(pc);//错误:const_cast只改变const属性
char *q=static_cast<char*>(pc)//错误:static_cast不能修改const属性
注意,上面修改的只是指针或引用的const属性,而非变量的const属性,想要通过修改*p来修改a是错误的,这是未定义行为。
那它有什么用?
1. 给非const形参传入const实参[1]
一些人声明函数类型时,即使在函数里不修改指针的值,也不声明为const,比如void log(char* msg);
明明只是用来把msg打印出来,却不加上const,c++编译器不允许你直接把const指针直接丢给char*,会报错。我们只好把手上的const指针转为非const再传给它。
2. 用于函数重载的场合
看个例子
const string &shorterString(const string &s1,const string &2)
{
return s1.size()<=s2.size()?s1:s2;
}
这个函数比较两个字符串并返回比较短的那个,参数和返回类型都是const string的引用,可以传入const实参或者非const实参(见:
C++学习笔记之顶层const和底层const),但返回结果仍然是const string的引用。现在我们想要重载这个函数,当实参不是const时,得到普通的引用:
string &shorterString(string &s1,string &2)
{
auto &r=shorterString(const_cast<const string&>(s1),
const_cast<const string&>(s2));
return const_cast<string&>(r);
}
这里用const_cast先将实参转换为const string&类型以传入上一个版本的函数,然后又用const_cast将返回值修改为普通的string&类型。
- reinterpret_cast
reinterpret_cast为运算对象的比特层面上提供较低层次的重新解释(我也不懂,有空再了解)
int *ip;
char *cp=reinterpret_cast<char*>(ip);
注意,cp实际上指向一个int对象而非char对象,尽管它是char型指针,如果把它当字符指针用可能在运行时出错
string str(cp);//错误
使用reinterpret_cast非常危险,尽量别用。
参考资料:
[1]关于const的几点疑问
[2]《C++ Primer》第5版