对于C语言的松散类型转换,Stroustrop采取的措施是更严格地限制允许的类型转换,并添加4个类型转换运算符,使转换过程更规范:dynamic_cast;const_cast;static_cast;reinterpret_cast; 可以根据目的选择一个更适合的运算符,而不是使用通用的类型转换。这指出了进行类型转换的原因,并让编译器能够检查程序的行为是否与设计者想法吻合。 使用这四种类型转换运算符不需要导入其它的头文件,以及任何namespace。因为他们是运算符,地位和sizeof( )、+ 、/ 等一致。
dynamic_cast 类型转换运算符
1dynamic_cast运算符的用途是使得能够在类层次结构中进行向上转换(属于is-a关系,这样的类型转换是安全的),而不允许其它类型转换。该运算符的语法如下:dynamic_cast (experssion) //注意必须有这对小括号,下同
2dynamic_cast运算符已经在前面介绍过了。总之,假设High和Low是两个类,而ph和pl类型分别为High *和Low *,则仅当Low是High的可访问基类(直接或间接)时,下面的语句才将一个High *指针赋给(转换成Low *)pl:pl = dynamic_cast ph; 否则,该语句将空指针赋给pl,即pl = NULL或pl = 0。
const_cast 类型转换运算符
1const_cast运算符用于执行只有一种用途的类型转换,即改变为有或无const或volatile(注:volatile adj.易变的)特征,其语法为:const_cast (expression) 如果类型的其他方面也被修改,则上述类型转换将出错。也就是说,除了const或volatile特征(有或无)可以不同外,type_name和expression的类型(指数据类型)必须相同。
2const_cast只能去除指针上的const属性,而不能去除已经定义好的变量上的const属性(如,const int counter),因为变量的存储类型一旦定义后就能不能改变。因此对除指针、数据成员指针、引用外的const类型变量使用const_cast类型转换符是非法的。const int counter = 0;int num = 12;num = const_cast (counter); //invalid #1//------------------- convert 'const int *' to 'int *' -------------------//const int * pInt = #int * iptr = const_cast (pInt); //valid #2//------------------- convert 'int * const' to 'int *'-------------------//int * const icptr = #iptr = const_cast (icptr); //valid #3//------------ convert 'const int * const' to 'const int *' ---------//const int * const cicptr = #pInt = const_cast (cicptr); //valid #4//---------------- convert 'int * const' to 'int *' ---------------//int * const icptr = #iptr = const_cast (icptr); //valid #5//----------- convert 'const int * const' to 'int *' ---------//iptr = const_cast (cicptr); //valid #6//----------- #1编译错误提示 在类型‘int’上使用 const_cast 无效,因为它既不是指针,也不是引用,也不是数据成员指针。
3假设High和Low是两个类:High bar;const High *pbar = &bar;……High * pb = const_cast(pbar); //validconst Low *pl = const_cast(pbar); //invalid 第一个类型转换使得*pb成为一个可用于修改bar对象值的指针,它删除const标签。第二个类型转换是非法的,因为他同时尝试将类型从const High * 改为const Low *。 提供该运算符的原因是有时候可能需要这样的一个值,它在大多数情况下是常量,而有时候又是可以修改的。在这种情况下,可以将这个值声明为const,并在需要的时候修改它的时候使用const_cast。
4补充:volatile 关键字作用:volatile 屏蔽系统对变量可能的优化;volatitle 这个关键字表述的问题一般都比较底层。应用场景:1) 并行设备的硬件寄存器(如:状态寄存器)几乎所有的 GPIO 的描述都包含这个关键字;#define inp(port) (((volatile byte ) (port)))2) 一个中断服务子程序中会访问到的非自动变量3) 多线程应用中被几个任务共享的变量
5const_cast类型转换举例:#include using std::cout;using std::endl;void change(const int * pt, int n ){ int *pc; pc = const_cast(pt); *pc += n;}//int main( ){ int pop1 = 38383; const int pop2 = 2000; cout << 'pop1, pop2: << pop1 << ',' << pop2 << endl; change(&pop1, -103); change(&pop2, -103); cout << 'pop1, pop2:' << pop1 << ',' << pop2 << endl;}//----------------- Out put: -----------------//pop1,pop2:38383,2000pop1,pop2:38280,2000
static_cast 类型转换运算符
1static_cast运算符的语法与其他类型转换运算符相同: static_cast (expression) 仅当type-name可被隐式转换为expression所属的类型或expression可被隐式转换为type-name所属的类型时,上述转换才是合法的,否则将出错。假设High是Low的基类,而Pond是一个无关的类,则从High到Low的转换、从Low到High的转换都是合法的,而从Low到Pond的转换是不允许的: High bar; Low blow; ... High *pb = static_cast (&blow); //valid upcast Low *pl = static_cast (&bar); //valid downcast Pond *pmer = static_cast (&blow); //invalid, Pond unrelated 第一种转换是合法的,因为向上转型可以显示地进行。 第二种转换是从基类指针到派生类指针,在不进行显示类型转换的情况下,将无法进行。但由于无须进行类型转换,便可以进行另一个方向的类型转换。因此使用static_cast来进行向下转换是合法的。 第三种转换是无法满足前面加粗文字描述的规则,所以是非法的转换。
2同样,由于无须进行类型转换,枚举值就可以被转换成为整型,所以可以用static_cast将整型转换为枚举值。可以使用static_cast将double转换为int、将float转换为long以及其它各种数值转换。
reinterpret_cast 类型转换运算符
1interpret [美]ɪnˈtɜ:rprɪt vt.解释;reinterpret [美]ˌri:ɪnˈtɜ:rprɪt vt.重新解释 摆上两个单词是想表达reinterpret_cast类型转换运算符的作用,其作用就如其名——将一种类型重新转换为另一种类型(两种类型甚至毫无关系)。 reinterpret_cast运算符用于天生危险的类型转换。它不允许删除const,但会执行其它令人生厌的操作。有时候程序员必须做一些依赖实现的、令人生厌的操作,使用reinterpret_cast运算符可以简化对这种行为的跟踪工作。该运算符的语法与另外3个相同: reinterpret_cast (expression);
2下面是一个使用示例:struct dat{ short a; short b;};long value = 0xA224B118; // long即long int简写dat *pd = reinterpret_cast (&value);cout << std::hex << pd->a; //display first 2 bytes of value 通常,这样转换适用于依赖实现的底层编程技术,是不可移植的。例如,不同的系统存储多字节整型时,可能以不同的顺序存储其中的字节。
3然而,reinterpret_cast运算符并不支持所有的类型转换。例如,可以将指针类型转换为足以存储指针表示的整型,但不能将指针转换为更小的整型或浮点型。另一个限制是,不能将函数指针转换为数据指针,反之亦然。
小结
在C++中,普通类型转换也受到限制。基本上,可以执行其它类型转换可以执行的操作,加上一些组合,如static_cast或reinterpret_cast后跟const_cast,但不能执行其它转换。因此,线面的类型转换在C语言中是允许的,但在C++中通常不允许,因为对于大多数C++实现,char类型都太小,不能存储指针: char ch = (char) &d; 这些限制是合理的,如果您觉得这种限制难以忍受,可以使用C语言。