类型安全
文章首先说什么是类型安全,其实定义并不简单,变量在定义之后,没有经过任何显示或者隐式的转换前,都是安全的。安全意味着什么?意味着变量,函数参数,返回值存储着一种可接受的数据,可接受意味着,和这些数据相关的操作是有意义的,合理的,不会有数据的丢失,不会被错误的解析,不会被污染,但是同时数据转换又是需要的。但是很多时候这种转换都是不安全的,只要是会引起数据丢失或者数据被重新解释的情况,都可以说是不安全的。比如int转为float,unsigned 转为 signed。
编译器的反映
对于不安全的转换,编译器有两个反映,一个种是error,一种是warning。而且就算编译器没有告警,错误还是可能被隐式转换或者显示转换引入。
隐式转换
当表达式中存在不相同的数据类型时,编译器就会按照内建的标准转换约定对数据进行转换。如果转换是一个promotion,我也不清楚该怎么翻译,那么编译器不会产生任何告警,而如果转换是narrowing,那编译器就会告警,因为存在数据的丢失。并建议我们将这种告警当作错误来看待。比如double变量复制给float变量。在cpp中,更多涉及的是用户定义的类型,这事编译器会从类型定义中常识找到可以接受的转换,否则,编译器将会报错。当然,这也是有一定的标准的。可以参见连接中的说明。
宽转换
宽转换就是上一段中说的promotion,不会导致数据丢失,所以都是安全的。编译器自然也不会告警。宽转换或者窄转换都都可能隐式得进行。在窄转换中,进过确认没有问题时,建议改为显示转换,这样编译器也就不会报错。
unsigned 和 signed
这两者之间的转换是没有任何告警的,所以在代码中,我们尽量避免直接的转换,至少在转换前需要对值的范围进行判断。
显示转换
除非两个类型完全不相关,否则编译器一般不会报错。就算有时候是不安全的,也只是会告警而已。
转换语法
C语言中的类型转换用的是小括号,而小括号在cpp里也是一中运算符。所以C语言的转换语法,在cpp里就等同于调用operator(),所以很多时候这也是不用一察觉的一种方式。不管是下面两种中的哪种,都是不好的方式:
(int)x
int(x)
因为这两种方式都不用意看出来,而且也不方便搜索。所以建议使用如下几种cpp语法的新的显示转换语法:
- static_cast 编译时类型校验,一般这也用在基类指针和派生类指针之间转换使用。既然是编译型校验,那就是在编译时就对错误进行检测,如果两种类型无法兼容,那么这个转换就会报错。
- dynamic_cast:运行时转换,据说这个比static_cast安全,但是也需要有跟多的开销。
- const_cast:一般用在const转非const,感觉应该用的不多。
- reinterpret_cast 不相关类型之间的转换,比如 pointer to int
于是下一个问题是,const_cast有什么意义,是不是另外构造了一个值?实现原理是怎样的?