c++primer第四章 表达式

左值、右值
当一个对象被当做右值的时候使用的是对象的值(内容),当对象被用作左值的时候用的是对象的身份(内存);
原则:在使用右值的地方可以用左值代替,但是不能把右值当成左值(也就是位置)使用。当一个左值被用工作右值时,实际上使用的是她的内容(值)。
1.赋值运算需要一个左值作为左侧运算对象,得到结果仍然是左值
2. 取地址符作用于一个左值对象,返回一个指向该对象的指针,这个指针是右值
3. 内置解引用运算符、下标运算符,迭代器解引用运算符,string、vector的下标运算符的求值结果都是左值
4. 内置类型和迭代器的递增递减运算符作用于左值运算对象,其前置版本所得结果也是左值
使用decltype时候,左值右值也有所不同,如果表达式求值结果是左值,decltype作用于该表达式得到一个引用类型。设p是一个 int * ,解引用得到左值,所以decltype( * p) 的结果是int&;另一方面,取地址得到右值,所以decltype(&p)得到int * *

4.1.3求值顺序
1. 逻辑与&& 运算符先求左侧对象的的值,左侧为真时才继续求右侧对象的值
2. 逻辑或 || 运算符也是先求左侧对象的的值,当且仅当左侧运算对象无法确定表达式结果时(为假)才继续求右侧对象的值;这种策略称为短路求值
3. 条件运算符 (?:)cond?expr1:expr2;
cond为真时求expr1的值并返回该值,否则计算expr2并返回;当俩个表达式都是左值或者都能转换成同一种左值类型时,运算结果是左值,否则 运算结果是右值;
4. 逗号运算符(,)先求左侧表达式的值然后丢弃掉,逗号运算符的真正结果是右侧表达式的值,右侧对象是右值就是右值,否则就是左值
运算对象的求值顺序与优先级和结合律无关
建议:
1.拿不准的时候最好使用括号来强制让表达式组合关系符合程序逻辑要求
2.如果改变了某个运算对象的值,在表达式的其他地方就不要再使用该对象;2的一个列外是,当改变运算对象的字表达式本身就是另外一个字表达式的的运算对象时该规则无效

赋值运算符满足右结合律

4.5递增递减运算符
前置版本 ++i (–i)和 后置版本 i++(i–)
* 前置版本先把对象加1(或减1),然后将改变的对象作为求值结果;后置版本也把对象加1(或减1),但是求值结果式运算对象改变之前那个值的副本
int i=0,j;
j=++i;//i=1,j=1;得到递增之后的值
j=i++;//j=1,i=2;后置版本得到递增之前的值
建议:除非必须,否则不用递增递减运算符的后置版本(后置版本还要存储修改前的值)
在一条语句混用解引用和递增运算符:如果既想使用原来的值又想递增变量就可以使用后置版本
auto pbeg=v.begin();
while(pbeg!=v.end()&&*pbeg>=0)
 cout << *pbeg++;//输出当前值,并向前移动一个元素
如果一条表达式改变了变量的值而另一条表达式要使用该值,运算顺序就很关键了

成员访问运算符:点运算符 箭头运算符
ptr->mem;相当于(*ptr).mem
string s=”a strig”, *p= & s;
auto n=s.size();
n=(*p).size();
n=p->size();

4.8位运算符

4.9sizeof运算符

sizeof运算符返回一个表达式或者一个类型名字所占的字节数,满足右结合律,返回类型size_t
两种形式:
sizeof(type)
sizeof expr;
第二种形式中,sizeof返回的是表达式结果类型的大小
Sales_data data ,*p;
sizeof(Sales_data); // 存储Sales_data 类型的对象所占的空间
sizeof data;//data类型的大小,同上
sizeof p;//指针所占空间大小;
sizeof *p;//p所指类型的大小
* 对char或者类型为char的表达式执行sizeof,结果是1;
* 对引用类型执行sizeof得到的是引用对象所占空间大小
* 对指针执行sizeof得到的是指针本身所占空间大小
* 对解引用执行sizeof运算得到指针指向的对象所占空间大小,指针不需要有效;
* 对数组执行sizeof得到整个数组所占空间大小 ,等价于对数组所有对象执行一次sizeof并将结果相加求和,sizeof不会把数组当做指针来运算
* 对string或者vector执行sizeof运算只返回该类型固定部分的大小,不会计算对象中元素占了多少空间
sizeof(ia)/sizeof( *a)得到数组中元素的个数

类型转换

  • 隐式转换 c++不会直接将两个不同类型相加,而是先根据类型转换规则设法将对象同一类型再求值;例如:int val=3.141+3;算术类型之间的隐式转换被设计成尽量避免精度损失;上面列子3先转换成double类型,然后执行浮点数加法,所得结果类型是double;接下来完成初始化任务;
  • 大多数表达式中比int小的整形首先提升为较大的整形
  • 条件中,非布尔值转换成布尔类型
  • 初始化中初始值转成变量类型;在赋值语句中右侧对象转换成左侧运算对象的类型。
  • 算数或者关系运算有多种类型需要转换成同一种类型
  • 函数调用也会发生类型转换
  • 运算符的运算对象将转换成最宽的类型;整形和浮点型运算整形提升为浮点型;如果long double参与其他类型会转成long double
  • 整形提升:这种规则负责把小整形提升为较大整形;对于bool、char、signed char、short 、 unsigned short只要所有可能值都能存在int里,他们就会转成int
  • 把一个负数转成一个无符号数会带来副作用,相当于负数加上无符号数的摸
  • 数组转成指针,大大多数用到数组的表达式中,数组自动转成指向数组首元素的指针
  • 当数组被用作decltype关键字的参数,或者作为取地址符&、sizeof及typeid等运算符的运算对象时,上述转换不会发生
  • 指向任意费常量的指针能转换成void*
  • 指向任意对象的指针能转换成const void *
  • 有继承关系的类型间还有另一种转换方式】
  • 转成常量:允许将指向非常量的类型的指针转换成相应的指向常量类型的指针;对于引用也是这样,反过来不行;
  • 类类型的转换,类类型能定义由编译器自动执行的转换,但是一次只能执行一种类类型转换,多个会被拒绝;p263
  • 显式转换:命名的强制类型转换:
  • cast_name(expression);
  • static_cast;任何具有明确意义的转换,只要不包含底层const都可以使用
  • dynamic_cast;支持运行时类型识别
  • const_cast ; 只能改变运算对象的底层const,
  • reinterpret_cast:比较危险,不建议使用;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值