c++ primer第四章——表达式

本章内容繁杂且没有什么规律,却是极其重要的一讲。
4.1基础部分
1.一元运算符和二元运算符,这二者继承自c语言,一元运算符指对一个对象进行运算,二元运算符则是对俩个对象进行运算,例如*,==,就是对俩个对象进行运算,而*,&是一元运算符
2.组合运算符和运算对象:对于含有多个运算符的复杂表达式来说,要想理解他的含义必须理解运算符的优先级和结合律,稍后会介绍这一点。
3.运算对象的转换:很多时候其实类型不同的对象也可以存在与同一表达式(只要他们可以转换为同一类型)
4.重载运算符:当运算符作用与类类型的运算对象时,用户可以自行定义其含义。这种行为类似于重载,因此又叫重载运算符(overloaded operator)。i/o库中的<<,>>都是重载运算符。
5.左值和右值:c++的表达式只存在右值和左值,当一个对象被当作右值时,用的是对象的值,当作左值是,用的是对象的身份,即使用他的位置。
4.1.2优先级和结合律
复合表达式(compound expression)是指含有俩个或多个运算符的表达式。**编写程序时可以用括号来辅助运算。
4.1.3求值顺序
对于那些没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象,将会引发错误以及未定义的操作,eg:
cout<<i<<""<<++i<<endl;//未定义的。因为表达式不知道先进行++i还是i。
另外明确规定了求值顺序的只有&&,||,?:,和逗号运算符。大多数情况没有指定求值

算术>关系>逻辑 (注意逻辑!的顺序)
4.2算术运算符
算术运算符
运算符 功能 用法

  • 一元正号 + expr
  • 一元负号 - expr
  • 乘号 expr*expr
    / 除法 expr/expr
    % 求余 expr%expr
  • 加法 expr+expr
  • 减法 expr-expr
    ***一元负号运算符对运算对象值取负后,返回其副本 eg:
    bool b=ture;
    bool b2=-b;//b2是ture!因为-b是-1,而不是0!因此说bool值不适合加入运算中。
    整数相除的结果还是整数,小数部分直接舍弃(注意不是四舍五入)
    (-m)/n m/(-n)都等于-(m/n)
    %取模运算负责计算两个整数相除所得余数,参与运算的对象必须是整数类型
    m%(-n)等于m%n (-m)%n 等于-(m%n)
    4.3逻辑和关系运算符
    结合律 运算符 功能 用法
    右 ! 逻辑非 !expr
    左 < 小于 expr<expr
    左 > 大于 expr>expr
    左 <= 小于等于 expr<=expr
    左 >= 大于等于 expr>=expr
    左 == 相等 expr==expr
    左 != 不等于 expr!=expr
    左 && 逻辑与 expr&&expr
    左 || 逻辑或 expr||expr
    **&& 两个运算对象为真时结果为真,|| 只要一个运算对象为真结果为真
    这个会进行短路求值,&& 第一个条件为真才对第二个求值
    || 第一个条件为假才对第二个求值
    几个关系运算符连写在一起会产生意想不到的结果if(i<j<k)这个是将I<j的运算结果和k比较
    4.4赋值运算符
    赋值运算符的左边必须是一个左值
    赋值运算符满足右结合律
    ***int i=j=0;//成立,都被赋值为零.J先被赋值
    复合赋值运算符
    += -= *= /= %= <<= >>= &=
    ^= |= 等价 a=a op b;
    4.5递增和递减运算符
    递增或递减运算符有前置和后置版本,前置版本就是在表达式之前将对象加一,而后置版本完成这一过程是在调动对象后
    int i=0,j;
    j=++i;//j=1,i=1:前置版本得到递增之后的值
    j=i++;//后置版本得到递增之前的值
    *pbeg++

运算对象可按任意顺序求值
while(beg != s.end() && !isspace(*beg))
*beg=toupper(*beg++);
这个东西会产生未定义行为
4.6成员访问运算符->
eg:ptr->mem;等价于(*ptr).mem;
4.7条件运算符
条件运算符?:是if else的另一种形式。
cond ? expr1 : expr2
finalgrade=(grade>90)?“high pass”: (grade <60) ? “fail” : “pass”;
//表达式成立,则返回第一个,反之,返回第二个。

4.8位运算符
数据在计算机内存中是以二进制存储的。
几种常用的位运算:
位与&: 对应位均为1时为1,其它为0。
位或|: 对应位均为0时为0,其它为1。(至少一个1)
位异或^: 对应位不相同时为1,相同时为0.(有且只有一个1)
位求反~: 每一位取反
右移>>: 将二进制进行右移,低位丢掉,高位补零。
左移<<: 将二进制进行左移,低位补零,高位丢掉。

4.9 sizeof()运算符
sizeof()运算符返回一条表达式或一个类型名字所占的字节数。
eg:Sales_data data,*p;
sizeof(sales_data);//返回一个sale_data的所占字节数
sizeof data;//同上
***sizeof()运算符的结果部分地依赖于其作用的类型
1.对char类型的表达式执行sizeof,得1
2.对引用类型执行sizeof,得被引用类型的大小
3.对指针执行sizeof(),得到指针本身所占空间的大小
4.对解引用指针,得到指针所指向对象类型的大小。
5.对数组执行sizeof,得到数组所占空间的大小,等价于对数组中所有元素各执行一次然后求和。
6.对string对象或vector对象执行sizeof运算只返回该类型固定部分的大小,不会计算对象中元素占用多少空间
4.10逗号运算符
逗号运算符含有俩个运算对象,按照从左往右的顺序依次取值。首先求出左侧表达式的值,然后将左侧表达式的值抛弃掉,他的真实值是右侧表达式的值

4.11类型转换
隐式转换 :自动执行 无须程序员介入
常见隐式转化
算术转换
1.对于bool, char,signed char, unsigned char,short, unsigned short等类型来说,它们都有可能通过整型提升变为int型。如:
a:false提升成了0,true提升了为1
b:
3.14159L+‘a’;

在这个加法运算中,小写字母‘a’是char型的字符常量,它其实能表示一个数字值,到底这个数字值是多少完全依赖于机器上的字符集。当把‘a’ 和一个long double类型的数相加时,char的值首先被提升成int,然后int 类型的值再转化为long double
c:
无符号类型不小于带符号类型,带符号的会被转换成无符号的
带符号类型大于无符号类型,如果无符号类型的所有值都能存在该带符号类型中,则转成带符号,不能则转成无符号
假如两个类型分别是 unsigned int 和 int,则int类型的运算对象会转换为unsigned int

大量例子
bool flag; char cval; short sval; int ival; long lval; float fval; unsignedshort usval; unsigned int uival; unsigned long ulval; double dval;
3.14159L+’a’ //’a’提升成Int,然后该Int值转换成long double
dval+ival; // ival转换成double
dval +fval; // fval转换成double
ival =dval; //dval转化成int
flag=dval; //dval是0,为false ,否则true
cval+fval;//cval提升成int ,该Int转换成float
sval+cval;//sval和cval都提升为int
cval+lval;//cval转换成long
ival+ulval;//ival转换成unsigned long
usval+ival;//根据unsigned short和int所占空间的大小进行提升
uival+lval;//根据unsigned int 和Long所占空间大小进行转换

其他隐式转换
数组转换为指针
在大多数用到的数组表达式中,数组自动转换为指向数组首元素的指针:
int ia[10]; /含有10个整数的数组/
int *ip=ia; /ia转换成指向数组首元素的指针/
单当数组被用作decltype关键字的参数,或者作为取地址符,sizeof 及typeid等运算符的运算对象时,上述转换不会发生。
指针的转换
1.转换为布尔类型
char cp=get_string();
if(cp) /
… */ //如果cp不为0,则条件为真
while(cp) //如果cp不是空字符,则条件为真
2.转换成常量
int i;
const int &j=i; //非常量转换const int的引用
const int *p=&i; //非常量的地址转换成常量的地址
int &r=i, *q=p;//错误:不允许const转换为非常量
3.类类型的转换:
string s;
while(cin>>s) // cin转换成布尔值

显示转换
cast-name (expression)
type 是转换的目标类型 expression 是要转换的值
cast-name 是static_cast 、 dynamic_cast、const_cast、reinterpret_cast中的一种
2、static_cast
任何具有明确定义的类型转换,只要不包含底层const,都可以使用
double slope=static_cast(j) /i;
当我们执行了显示的类型转换后,警告信息就会被关闭
3、const_cast
只能改变运算对象的底层const
const char *pc;
char p=const_cast<char>(pc);
只有const_cast能改变表达式的常量属性,使用其他形式的命名强制类型转换改变表达式的常量属性都将引发编译器错误。同样的,不能用它改变表达式的类型
const char *cp;
const _cast(cp);//错误,只能改变常量属性
4、reinterpret_cast
通常为运算对象的位模式提供较低层次上的重新解释

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王蒟蒻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值