正文之前
学习,不如爆文?反正晚上也不会学习,某个家伙也对我爱理不理的!!!!(这才是最骚的吧),刚好欠了 C++ Primer太多烂账了。不如赶紧还了! 对了 Primer是初级,入门的意思哦~~是不是很操蛋,是的,我承认,我也觉得!!!!
正文
1、 算术类型之间的转换尽量避免损失精度
很多时候,如果表达式中既含有各种不同类型的运算对象,会存在各种各样的转换。那么很多时候,这种转换是存在了精度的损失的,比如下面这句:
int ival = 3.14 +1 ;
这里的话,最后要求ival是int 类型。所以这一点不容更改,我们要的是一个int类型的,那就不能用一个double类型的来返回给我的ival,所以上面这一句话经历了艰难险阻,首先是把1变成 1.0,然后 1.0+ 3.14 成为 4.14 这个时候再来返回一个右值给赋值语句。然后编译器发现,4.14 不是int类型啊。还好这是关联的类型,所以直接把 4.14 给直接削了成了 4 这就是常规意义上的精度损失。也就是说是我们要避免的。从 int 提升到 double 是可以的,虽然花费了更多的系统空间,但是我们的精度略有提升,还算是能承受的!
2、 何时发生隐式类型转换?
- 比int小的(一般是指位数,比如short这种16位的,int 是 32位)类型的整型值首先提升为整数类型
- 条件中, 非布尔类型转换成布尔类型
- 初始化过程中,初始值转变成变量的类型。赋值语句中右侧运算对象转换成左侧的运算对象
- 如果算数类型或者关系运算有多种类型,需要转换成一种
- 函数调用会发生类型转换
3、 算术转换
我个人认为其实就是因为原本的类型不足以概括整个表达式中的所有参与运算的运算对象的时候,会存在类型转换,书上说是将运算对象转换为最宽的类型。
- 整形提升
- bool
- unsigned char
- char
- signed char
- short
- unsigned char
以上几个类型,只要它们所有可能的值能存在于int 里面,它们就会提升成为int类型。否则 提升成 unsigned int类型。较大的char类型会提升成相匹配的长度最小的类型。
- 无符号类型的扩充
这个仔细看书比较好,我个人的认识就是,会把小类型的转换为大类型的。就比如说这个数能被另外一个更多位的类型容纳,并且在表达式内需要转换,那么就会如此转换。比如说int类型的值与unsigned int类型的相加,则把int 转换成 unsigned int 因为前者可以完全被后者包容。当然如果int表示的是一个负值。那么,妥妥的会从二进制给予转换成unsigned int类型。
跟图中一样的(我是六十四位系统!!)当给unsigned int类型的 b附一个负值的时候,自然就会爆炸了!! int 被自动提升!其他的int 到 float 到 double的类型转换就不说了,都是自然而然的事情。
4、 其他隐式类型转换
数组转换成指针
这个是前面讲烂了的。数组名就是首元素地址的指针。当然,有几个特例,比如说 decltype就完全不管你的指针元素,或者作为& 取地址符,sizeof、typeid 的运算对象的时候就不会发生上述转换。不过这些都是个例。我们平常大部分用到的数组名都还是首元素地址的指针。指针的转换
包含常量整数值0 或者字面值为nullptr的指针能转换成任何指针类型;指向任意非常量的指针可以转换成void * 但是无法通过转换后的指针解引用访问这个对象了!指向任何对象的指针都可以转换为 const void * 指针。
- 转化为布尔型
存在一种算数类型或者指针类型像布尔类型的自动转换的机制。比如大家伙常用的if(int) while(float) 都是把int float转换为bool 类型之后才会继续执行语句的!
- 转化成常量
允许将指向非常量的指针转化成指向相应的常量类型的指针,对于引用同样如此!
int i;
const int &j = i;
const int *p = & i;
int &r=j,*q=p; // 错误,不允许const转化为非常量。。
- 类类型定义的转换
我也不是很懂,举两个例子:
string s,t="a, value"; //字符串字面值转化为string类型
while(cin>>s) //while的条件部分是把cin转化为布尔值
5、 显示转换
- 命名的强制转换
总体的形式是/***** cast-name<type> (expression); *****/其中type是类型转换的目标,expression就是等待转变的值。如果type类型是引用的话,那么结果是左值。cast-name的话,按照新标准有static_cast、dynamic_cast、const_cast、reinterpret_cast中的一种,cast-name决定了具体的类型转换。
- static_cast
这个跟传统的强制转换很像。而且颇为适合用于大的数据类型转化为小的数据类型。等于是告诉编译器:我们不在乎精度损失,按我说的长度来吧!
double slope = static<double>(j) / i;
也可以用static_cast来找回void * 指针所指向的对象的内容。
void *p = &d;
double *dp = static_cast<double *> (p);
- const_cast
const_cast只用于修改运算对象的底层const ,而上面的static_cast则是无法修改底层const的内容。形成一种互补吧!这个转换的作用也可以称为“去const性质的转换” 看例子你就知道了
const char *pc;
char *p = const_cast<char *>(pc);
可以看到,如果没有const_cast,这个句子会因为pc具有底层const而报错,但是因为有了const_cast,所以我们可以完成从常量到非常量的转变。但是我们没法通过p修改值就有错误了。这是未定义的行为,当然const_cast我们都用的少,这个就更加不怎么担心了!
- reinterpret_cast
听说reinterpret_cast用起来十分危险,一不小心就会造成程序崩溃,所以为了大家的好习惯,我就不说了!自求多福吧
6、 旧式的强制类型转换
上面是不是说的有点头晕眼花??那就说个熟悉点的。老朋友,C语言风格的类型转换。
/***** (type) expr *****/
char *pc = (char *) ip ;
旧式的除了容易写这个优点外,存在容易看漏,而且转换出问题难以追踪的毛病,推荐新标准咯!
正文之后
面对一个开了贤者模式的大佬。我低下了我高傲的头颅,默默退出了谈话,心情久久不能平静。硬碰硬不是良道啊,生气这种事还是交给女生吧,我要不就不生气,生气一次就到底了吧。还好还好,暂时还没见到自己生气的样子,反正我很怕就是了,跟怕死差不多的节奏。。