const_cast
- const_cast是唯一能将const性质转化掉的操作符,但执行其他任何类型的转换都会引起编译错误。
单纯的把常量转为变量是没多少意义的,也就是这种代码:1
2const int con =12;
int cc= static_cast<int>(con);
直接用变量或者mutable就好了。
如果定义了一个非const的变量,却使用了一个指向const值的指针来指向它(不规范的风格),在程序的某处我们想改变这个变量的值了,但手头只持有指针,这是const_cast就可以用到了:1
2
3
4int constant = 26;
const int* const_p = &constant;
int* modifier = const_cast<int*>(const_p);
*modifier = 3;
这并不是一个好的设计,还是应该遵从这样的原则:使用const_cast
去除const限定的目的绝对不是为了修改它的内容,只是出于无奈,所以最好少用转型。
如果有一个函数,它的形参是non-const类型变量,而且函数不会对实参的值进行改动,这时我们可以使用类型为const的变量来调用函数,也就用到const_cast了。1
2
3
4
5
6
7
8
9void InputInt(int * num)
{
cout<<*num<<endl;
}
int main()
{
const int constant = 21;
InputInt(const_cast<int*>(&constant));
}
dynamic_cast
dynamic_cast用于类继承层次间的 指针或引用 的转换。和qobject_cast
类似,用于执行安全的向下转型
dynamic_cast
只能用于含有虚函数的类,虚函数表是是dynamic_cast操作符转换能够进行的前提条件。虚表的最前面是指向 type_info 的指针,包含了类的继承信息、类的描述等。能否转换成功,所依据的就是type_info
。如果转换失败,new_type 是指针,那么将返回NULL;如果 new_type 是引用,那么将抛出异常 std::bad_cast
向下转型有两种情况。一种是基类指针指向派生类的对象,这种转换是安全的;另一种是基类指针所指对象为基类类型,在这种情况下dynamic_cast在运行时做类型检查,转换失败,返回结果为0
最常用的情况是这样:1
2
3Base* bb = new Derive();
Derive* dd = dynamic_cast<Derive*>(bb);
dd->test();
如果没有虚函数,会报错: error: C2683: “dynamic_cast”:“Base”不是多态类型
dynamic_cast在基类和派生类指针之间转换时,会遍历整个继承体系进行类型检查,因此dynamic_cast时间和空间代价较高。比如4级的继承结构,dynamic_cast<Base>
将会调用4次才能确定最终的那个子类型,尤其避免连续使用转型,用虚函数代替这种情况。
static_cast
类似于C风格的强制转换。无条件转换,静态类型转换。用于:
子类转换为父类:其中子类指针转换成父类指针是安全的;但父类指针转换成子类指针是不安全的,此时用dynamic_cast
基本数据类型转换,例如double, int, char, float等,不能进行无关类型(如非基类和子类)指针之间的转换。
void*
转换为某类型指针
1 | double a = 1.999; |
大多数的编译器都会给出一个警告:从“double”转换到“int”,可能丢失数据。static_cast
可以明确告诉编译器,这种损失精度的转换是在知情的情况下进行的
1 | double a = 1.999; |
从这里能看出,static_cast进行的是简单粗暴的转换,static_cast不做运行时的类型检查以保证转换的安全性,所以static_cast不如dynamic_cast安全,其正确性完全由程序员自己保证。
reinterpret_cast
十分危险,平时不要使用。
从底层对数据进行重新解释,依赖具体的平台,可移植性差
可以在指针和引用随意的转换
可以将整型转换为指针,也可以把指针转换为数组