建议11:将强制转型减到最少
C++ 在设计中一直强调类型安全,而且也采取了一定的措施来保障这条准则的执行。但是,从C继承而来的强制转型却破坏了C++类型系统,C中的强制转型可谓是“无所不能”,其超强的能力给C++带来了很大的安全隐患。强制转型会引起各种各样的麻烦,有时这些麻烦很容易被察觉,有时它们却又隐藏极深,难以察觉。
在C/C++语言中,强制转型是“一个你必须全神贯注才能正确使用”的特性。所以一定要慎用强制转型。
首先来回顾一下C 风格(C-style)的强制转型语法,如下所示:
|
这两种形式之间没有本质上的区别。在C++中一般称为旧风格的强制转型。
在赋值时,强制类型的转换形式会让人觉得不精密、不严格,缺乏安全感,主要是因为不管表达式的值是什么类型,系统都自动将其转为赋值运算符左侧变量的类型。而转变后数据可能会有所不同,若不加注意,就可能产生错误。
将较大的整数转换为较短的数据类型时,会产生无意义的结果,而程序员可能被蒙在鼓里。正如下面的代码片段所示:
|
输出结果竟然成了-1。较长的无符号类型在转换为较短的有符号类型时,其数值很可能会超出较短类型的数值表示范围。编译器不会监测这样的错误,它所能做的仅仅是抛出一条非安全类型转换的警告信息。如果这样的问题发生在运行时,那么一切会悄无声息,系统既不会中断,也不会出现任何的出错信息。
类似的问题还会发生在有符号负数转化为无符号数、双精度类型转化为单精度类型、浮点数转化为整型等时候。以上这些情况都属于数值的强制转型,在转换过程中,首先生成临时变量,然后会进行数值截断。
在标准C中,强制转型还有可能导致内存扩张与截断。这是因为在标准C中,任何非void类型的指针都可以和void类型的指针相互指派,也就可以通过void类型指针这个中介,实现不同类型的指针间接相互转换了。代码如下所示:
|
指针pd指向的空间本是一个双精度数据,8字节。但是经过转换后,pi却指向了一个4字节的int类型。这种发生内存截断的设计缺陷会在转换后进行内存访问时存在安全隐患。不过,这种情况只会发生在标准C中。在C++中,设计者为了杜绝这种错误的出现,规定了不同类型的指针之间不能相互转换,所以在使用纯C++编程时大可放心。而如果C++中嵌入了部分C代码,就要注意因强制转型而带来的内存扩张或截断了。
与旧风格的强制转型相对应的就是新风格的强制转型了,在C++提供了如下四种形式:
|
新风格的强制转型针对特定的目的进行了特别的设计,如下所示。
const_cast<T*> (a)
它用于从一个类中去除以下这些属性:const、volatile和 __unaligned。
|
这种强制转型的目的简单明确,使用情形比较单一,易于掌握。
dynamic_cast<T*>(a)