1、 C 风格(C-style)强制转型如下:
(T) expression //cast expression to be of type T
函数风格(Function-style)强制转型使用这样的语法:
T(expression) //cast expression to be of type T
这两种形式之间没有本质上的不同,它纯粹就是一个把括号放在哪的问题。我把这两种形式称为旧风格(old-style)的强制转型。
2、 C++的四种强制转型形式:
C++ 同时提供了四种新的强制转型形式(通常称为新风格的或 C++ 风格的强制转型):
const_cast(expression)
dynamic_cast(expression)
reinterpret_cast(expression)
static_cast(expression)
每一种适用于特定的目的:
·dynamic_cast 主要用于执行“安全的向下转型(safe downcasting)”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。它是唯一不能用旧风格语法执行的强制转型,也是唯一可能有重大运行时代价的强制转型。
·static_cast 可以被用于强制隐型转换(例如,non-const 对象转型为 const 对象,int 转型为 double,等等),它还可以用于很多这样的转换的反向转换(例如,void* 指针转型为有类型指针,基类指针转型为派生类指针),但是它不能将一个 const 对象转型为 non-const 对象(只有 const_cast 能做到),它最接近于C-style的转换。
·const_cast 一般用于强制消除对象的常量性。它是唯一能做到这一点的 C++ 风格的强制转型。
·reinterpret_cast 是特意用于底层的强制转型,导致实现依赖(implementation-dependent)(就是说,不可移植)的结果,例如,将一个指针转型为一个整数。这样的强制转型在底层代码以外应该极为罕见。
旧风格的强制转型依然合法,但是新的形式更可取。首先,在代码中它们更容易识别(无论是人还是像 grep 这样的工具都是如此),这样就简化了在代码中寻找类型系统被破坏的地方的过程。第二,更精确地指定每一个强制转型的目的,使得编译器诊断使用错误成为可能。例如,如果你试图使用一个 const_cast 以外的新风格强制转型来消除常量性,你的代码将无法编译。
------------------------------------------------------------------------------------------------------------------------
以上为网上的教科书式概念,现在从一些具体用法上解释几者的区别。
1、dynamic_cast主要用于继承体系,而且是用于多态。将一个派生类的指针转化为基类的指针。其实这时是可以直接进行赋值的,不需要用此运算符。不过加上此运算符后,变的更加直接明了,便于检查。例如:
class A
{
public:
virtual ~A(){}
};
class B:public A
{
};
int main()
{
B* p = new B();
A* q = dynamic_cast<A*>(p); //其实也可以直接写成 A*q = p;
//如果反向的话,b的值为NULL。即使当两个类没有继承关系,进行dynamic转换时,也不会编译错误,但返回值会是NULL值。
A* a =new A();
B* b = dynamic_cast<B*>(a);
}
注意:如果将类A中的virtual去掉,使其没有虚函数,那么此时dynamic_cast就会产生编译错误,dynamic_cast的使用是要借助于虚表的。而虚表是虚类产生的。
2、static_cast用于大部分的类型转换。如:
1)数据类型的转换,如int转换为char,float转换为double型等等.
2)类层次结构中基类和子类之间指针或引用的转换。
A、进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
B、进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。(dynamic_cast进行下行转换时返回指针为空)。
3)当两个毫不相关的类的指针进行转换时,static_cast转换会发生编译失败。
3、const_cast用于去掉对象的常量性质,这是在c++里的唯一方法。例如:
char a = ‘a’;
const char* p = &a;
char* q = const_cast<char*>(p);
/* char *q = p; 这会发生编译错误的,因为如果这样成功的话,就可以对*q进行操作,那么就间接操作了*p,而此时*p是const型的,不能修改。所以只能通过const_cast进行强制取消常量性质。*/
*q = ‘b’;
//此时便可以对*q进行修改,同时也修改了*p,因为q和p指向的同一个地方。但是如果写成*p = ‘b’还是不允许的。
注意:
const int a =5;
int b = a;
这样写是允许,不需要用const_cast进行转换,因为b又是一个对象,对b的操作并不会影响a。如果出现了指针则要注意一下,要看const修饰的是指针,还是修饰的是指针所指的对象。例如
char* const p = &a;
char* q = p;
这样就是合法的,因为const修饰的是p指针。表示指针不会变换。char*q = p;是分配了一个新的指针q,对指针q或*q的操作并不会影响到p。
4、reinterpret_cast运算符主要是用于指针类型的转换,以及整型与指针的转换。转化的时候在底层只是简单的将内容按比特完全复制过去,然后按另一种方式进行解析。和static_cast不一样,例如static_cast将int转换为double时会将在内存中的值进行改变的,一开始是int的表示方式,后来就变成double类型在内存中的表示方式。所以如果用reinterpret_cast将int转换为double时,只是简单的位复制,然后按double型解释,那么解释出来的值完全和原值不一样了。这样是没什么意义的,也是不安全的。所以如果要进行内置变量转换,多用static_const。但是对于指针类型转换,用reinterpret_cast是合适的,因为指针在内存里面都是占四个字节,表示某个内存的地址。在指针类型转换时,并不需要指针的值进行变换(保持指向某块内存),只需让指针解释的方式发生改变即可。
举例:
int a = 83;
int* s = &a;
char* p = reinterpret_cast<char*>(s); //将整型指针转化为字符指针
int b = reinterpret_cast<int>(s); //将指针型转换为整型
float p = reinterpret_cast<float&>(a);//如果要进行内置数据类型的转换,则必须加上&符号,不知道为什么?
补充:(摘抄于参考文献3)
1、 static_cast和reinterpret_cast 的区别:
两者都可以用于指针、引用类型的转换,但static_cast主要用于“有关系(如继承关系)”的指针或引用之间的转换,多半是继承关系,而没有关系的指针之间的转换会发生编译错误。但如果是“有关系”的指针、引用类型进行转换时,我们又多采用dynamic_cast进行转换(可以进行安全性检查)。而reinterpret_cast可以用于任何指针之间的转换。前述三者都是不能取消对象的const属性,只能通过const_cast。
所以总结如下:
dynamic_cast用于有继承关系的指针或引用之间的转换。
static_cast用于基本数据类型或对象之间的转换。
reinterpret_cast用户没有关系的指针或引用之间的转换
const_cast用于去掉对象的const属性。
2、 对static_const不要望文生义,认为和const_cast是取消const一样,取消static属性。
3、 举一个例子:
#include <iostream>
using namespace std;
unsigned short Hash( void *p ) {
unsigned long val = reinterpret_cast<unsigned long>( p );
return ( unsigned short )( val ^ (val >> 16));
}
class Something
{
/* Some codes here */
};
class Otherthing
{
/* Some codes here */
};
int main() {
typedef unsigned short (*FuncPointer)( void *) ;
FuncPointer fp = Hash; //right, this is what we want
int a[10];
const int* ch = a; //right, array is just like pointer
char chArray[4] = {'a','b','c','d'};
fp = reinterpret_cast<FuncPointer> (ch); //no error, but does not make sense
ch = reinterpret_cast<int*> (chArray); //no error
cout <<hex<< *ch; //output: 64636261 //it really reinterpret the pointer
Something * st = new Something();
Otherthing * ot = reinterpret_cast<Otherthing*> (st); //cast between objects with on relationship
}
而以上转换,都是static_cast所不能完成的任务,也就是说把上边程序里所有的reinterpret_cast换成static_cast的话,就会立即得到编译错误,因为目标指针和原始指针之间不存在"关系"
从上边的程序,也就一下子看出来了reinterpret_cast和static_cast之间最本质的区别。
而以上转换,都是static_cast所不能完成的任务,也就是说把上边程序里所有的reinterpret_cast换成static_cast的话,就会立即得到编译错误,因为目标指针和原始指针之间不存在"关系"
从上边的程序,也就一下子看出来了reinterpret_cast和static_cast之间最本质的区别。
对于static_cast所需要的关系,"继承"绝对是其中之一,所以static_cast支持指向基类的指针和指向子类的指针之间的互相转换:
class Parents
{
public:
virtual ~Parents(){}
/*codes here*/
};
class Children : public Parents
{
/*codes here*/
};
int main()
{
Children * daughter = new Children();
Parents * mother = static_cast<Parents*> (daughter); //right, cast with polymorphism
Parents * father = new Parents();
Children * son = static_cast<Children*> (father); //no error, but not safe
}
但是从基类到子类的转换,用static_cast并不是安全的,具体的问题会在dynamic_cast一篇阐述。
在指针和引用方便,似乎也只有继承关系是可以被static_cast接受的,其他情况的指针和引用转换都会被static_cast直接扔出编译错误,而这层关系上的转换又几乎都可以被dynamic_cast所代替。这样看起来static_cast运算符的作用就太小了。
实际上static_cast真正用处并不在指针和引用上,而在基础类型和对象的转换上 。 而基于基础类型和对象的转换都是其他三个转换运算符所办不到的。
【参考】
1. http://www.cnblogs.com/ider/archive/2011/07/22/cpp_cast_operator_part2.html C++标准转换运算符const_cast
2. http://www.cnblogs.com/ider/archive/2011/07/30/cpp_cast_operator_part3.html C++标准转换运算符reinterpret_cast
3. http://www.cnblogs.com/ider/archive/2011/07/31/cpp_cast_operator_part4.html C++标准转换运算符static_cast
4. http://www.cnblogs.com/ider/archive/2011/08/01/cpp_cast_operator_part5.html C++标准转换运算符dynamic_cast
5. http://blog.csdn.net/wingfiring/article/details/633033 dynamic_cast详解