第四章
1
当一个对象用作右值,用的是对象的值。
当一个对象用作左值,用的是对象的身份(在内存中的位置)。
(&p
)指针是一个右值,因为你无法改变变量的地址,即无法对此处的指针进行修改。
decltype
对左值是int&
2
对于没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象,将会引发错误并产生未定义的行为:
cout<<i<<" "<<++i<<endl;
只有四种运算符明确规定了运算对象的求值顺序,第一种是&&
,第二种是||
,第三种是?:
,第四种是,
PS:相等性运算符是不规定运算对象的求值顺序的。
【如果改变了某个运算对象的值,在表达式的其他地方不要再使用这个运算对象】
3
运算优先级:
一元运算符最高
接下来是乘法和除法以及取模
优先级最低的是加法和减法
上述运算符都是左结合的。
逻辑非优先级很高,除此之外算术运算符高于关系运算符高于逻辑运算符:
[+]>[=]>[||]
4
C++11
开始,(-m)/n=m/(-n)=-(m/n)
,m%(-n)=m%n
,(-m)%n=-(m%n)
5
窄化转换需要注意截尾和舍入。
当赋值操作时,会强制转换。
当初始化列表即k={3.14}
时,由于窄化转换会错误。
【无论左侧对象的类型是什么,初始化列表都可以为空,此时编译器创建一个值初始化的临时量赋给左侧运算对象】
6
前置+
得到的是左值,后置+
得到的是右值;
*pedg++=*(pedg++)
,++
的优先级高于*
7
点运算操作的对象是左值,结果就是左值;是右值,结果就是右值。
8
条件运算符是右结合的:
a?b:c?d:e;
实际上是:a?b:(c?d:e)
,而不是(a?b:c)?d:e
,说明其是从右向左结合的。
PS:条件运算符的优先级特别低,所以一定要加括号,甚至比cout<<
还低
cout<<grade<3
也是一样错误的,<
运算符低于移位
9
位运算的时候,右侧的运算对象一定不是能是负数。
左移运算符在右侧插入0,右移运算符时如果运算对象是无符号类型则在左侧插入0,如果是带符号类型在左侧插入符号位的副本或值为0的副本。
10
sizeof p
或sizeof(p)
都可以获取对象所占的空间大小。
如果是表达式,则返回的是表达式结果类型的大小,它并不实际计算运算对象的值。
比如sizeof *p
,sizeof
是右结合的,所以等价于sizeof(*p)
。
即使p
是空指针,*p
也不会进行实际地访问,sizeof
会得到类型并不会实际访问,所以仍然是合法的。
PS:
1、对string
或vector
进行运算,只会返回类型固定部分的大小,不会计算对象中的元素占用过了多少空间。
2、sizeof
不会把数组转换成指针使用
3、操作系统的位数决定了指针变量所占的字节数。64
位就是8
(字节)
11
sizeof
优先级和++
一个梯队,所以:
(sizeof x) + y
;
sizeof (p->mem[i])
(sizeof a) < b
sizeof (f( ))
()
优先级在::
下,::
独一档。
12
算术转换:
1、整型提升:
小整数类型转换成较大的整数类型。优先变成int
,存不下就是unsigned int
较大的char
会提升到刚好满足的类型:int
、uint
、long
、…、unsigned long long
2、如果有无符号类型的运算对象
首先进行整型提升:
如果提升之后对了,就结束;
如果都是带符号或者不带,那么小的往大的靠。
如果一个带一个不带,且无符号不小于有符号,那么转换成无符号的:
int
→
\to
→unsgined int
如果有符号的更大,那么无符号的如果可以存到有符号类型里,那就变成有符号,否则就变成无符号。
long
和unsgined int
,并且int
和long
大小相同,则long
类型的转换成unsigned int
类型,如果long
类型占用的空间比int
多,则unsigned int
→
\to
→long
.
13
指向任意非常量的指针可以转换成void*
指向任意对象的指针能转换成const void*
14
显式转换
static_cast
:
任何具有明确定义的类型转换,只要不包含底层const
,都可以static_cast
。
double slope=static_cat<double>(j)
当需要把一个较大的算术类型赋值给较小的时,其非常有用。
它也可以找回存在于void*
指针的值:
double *dp=static_cast<double*>(p);
当我们把指针存放在void*
中,并且使用static_cast
将其强制转换回原来的类型时,应该确保指针的值保持不变。
const_cast
:
只能改变运算对象的底层const
const char*pc;char *p=const_char<char*>(pc);
如果对象本身是常量,写操作可能会有未定义行为。
reinterpret_cast
:
reinterpret_cast
通常为运算对象的位模式提供加低层次上的重新解释。
什么都可以转,所以很危险
dynamic_cast
:参考
用于动态类型转换。只能用于含有虚函数的类,用于类层次间的向上和向下转化。只能转指针或引用。向下转化时,如果是非法的对于指针返回 NULL,对于引用抛异常。要深入了解内部转换的原理。
向上转换:指的是子类向基类的转换
向下转换:指的是基类向子类的转换
它通过判断在执行到该语句的时候变量的运行时类型和要转换的类型是否相同来判断是否能够进行向下转换。