五大cast转型

const_cast

  • const_cast是唯一能将const性质转化掉的操作符,但执行其他任何类型的转换都会引起编译错误。

单纯的把常量转为变量是没多少意义的,也就是这种代码:

1
2
const int con =12;
int cc= static_cast<int>(con);

直接用变量或者mutable就好了。

如果定义了一个非const的变量,却使用了一个指向const值的指针来指向它(不规范的风格),在程序的某处我们想改变这个变量的值了,但手头只持有指针,这是const_cast就可以用到了:

1
2
3
4
int 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
9
void 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
3
Base* 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
2
double a = 1.999;
int b = static_cast<double>(a); //相当于a = b ;

大多数的编译器都会给出一个警告:从“double”转换到“int”,可能丢失数据。static_cast可以明确告诉编译器,这种损失精度的转换是在知情的情况下进行的

1
2
3
4
double a = 1.999;
void * vptr = & a;
double * dptr = static_cast<double*>(vptr);
cout<< *dptr <<endl; //输出 1.999

从这里能看出,static_cast进行的是简单粗暴的转换,static_cast不做运行时的类型检查以保证转换的安全性,所以static_cast不如dynamic_cast安全,其正确性完全由程序员自己保证。

reinterpret_cast

十分危险,平时不要使用。

  • 从底层对数据进行重新解释,依赖具体的平台,可移植性差

  • 可以在指针和引用随意的转换

  • 可以将整型转换为指针,也可以把指针转换为数组

qobject_cast

参考:qobject_cast 分析及QTBUG 20616