c++相对于c在强制类型转换上的区别还是很大的,除了引入了c中不可能有的dynamic_cast外还将原c中的强制类型转换:(Type_name)expr分拆变成几个不相交的强制类型转换:static_cast,const_cast,reinterpret_cast
首先从由简单到复杂分别解释这三个不相交的强制类型转换在指针和引用上的表现:
const_cast<T*>(expr) 或 const_cast<T&>(expr)(以后就只写指针的形式,毕竟指针和引用在编译后的代码上没有区别):如其名所示是随意改变某个表达式的const性和volatile的,其他的功能概不具有,eg:
const int i = 0;
*const_cast<int*>(&i) = 1;
这样就将常量的值修改了,但是我觉得如果是用了这样的强制类型转换只能说明当初不该将i声明,定义成为const的
同理引用方式也可以,不过引用用于将变量或者变量的引用转换,eg:
const int i = 0;
const_cast<int&>(i) = 1;
reinterpret_cast<T*>(expr):如其名就是将表达式所示的地址的内容用另一种方式来表达,其实这个强制类型转换最简单,就是将类型改变了,但是对const性volatile性都没有权利改变,eg:
//以下的代码可以查看仅仅32bit中的头一位为1的时候float类型数据的值是多少
const int i = 1;
cout << reinterpret_cast<const float&>(i) << endl;
static_cast<T*>(expr):如其名是静态类型转换,就是在编译的时候就可以进行的转换,能够正确的确定转换后的表示.在《c++语言的设计和演化》一书中有种说法:只要T->S能够隐式完成它就能进行S->T的转换(当然隐式完成的也可以强制完成,用以消除warning).对于指针来说,隐式转换很少,就我现在能够想到的是:任意指针到void*指针的转换(const性相同),派生类指针到基类指针的转换,eg:
//以下的代码和上段的代码结果相同,却没有用到reinterpret_cast,是因为void*指针从中作梗
float d = 0;
void* pv = &d;
*static_cast<int*>(pv) = 1;
cout << d << endl;
在指针和引用上强制类型转换的介绍就到此,重要的是任意类型的强制类型转换,由于指针和引用的都介绍过,以下就是除此以外的类型转换:
仍然按照从简单到复杂的顺序来进行:
reinterpret_cast<T>(expr):只支持指针和引用
const_cast<T>(expr):一点作用都没有的转换,我想不出来这个有什么用,用来将const去掉?但是去掉了又有什么用,所有的cast的结果都是通过expr生成的一个右值注1,试问一个右值可以做什么,所以编译器就压抑了这种用法,其实还是可以理解的,eg:
const int i = 0;
const_cast<int>(i);//error C2440: 'const_cast' : cannot convert from 'const int' to 'int' Conversion is a valid standard conversion, which can be performed implicitly or by use of static_cast, C-style cast or function-style cast
可以用一个方式来解释:int j = i;是合法的,所以是valid standard conversion
static_cast<T>(expr):语法上就和前面提到的《c++语言的设计和演化》书中说法一致,至于一些细节有点多(主要存在于派生当中),以后再写.
注1:
在c++0x中提出了右值引用,这样可以方便的捕获那些值是右值,编写一个捕获右值的函数就可以查看当前的这个值是否是右值.函数的编写又会引入新的问题,以后再说明.