C++Primer 4.5-4.9 几种运算符

4.5 递增和递减运算符

递增运算和递减运算符为对象的加1和减1提供了一种简洁的书写形式,这两个运算符还可以用于迭代器(函数重载得到的)。
递增和递减运算符有两种形式:前置版本和后置版本。

前置版本(++i,–i):这种形式的运算符首先将运算对象加1(或减1),然后将改变后的对象作为求值结果。
后置版本(i++,i–):也是讲运算对象加1(或减1),给、返回的结果为运算对象改变之前的副本。

建议:除非必须,否则不用递增递减运算符的后置版本。
原因其实非常简单:前置版本的递增递减运算避免了不必要的工作(将值加一或减一直接返回改变后的运算对象),与之相比,后置版本需要将原始值存储下来以便返回这个未修改的值,倘若我们不需要修改前的值,那么使用后置版本就是一种浪费。

在一条语句中混用解引用和递增运算符

若想将变量加1或减1,同时需要使用修改前的值,在这种请况下就应该使用递增和递减运算符的后置版本。
例如:输出vector对象的内容直至遇到第一个负值(不包括)

auto pbeg = v.begin();
while(pbeg != v.end() && *pbeg >= 0)
    cout << *pbeg++  << endl;

关于代码 *pbeg++ ,后置递增运算符的优先级要高于解引用运算符,因此该代码等价于
*(pbeg++)。(这种写法十分简洁并且不易出错,提倡这么写)

4.6 成员访问运算符

点运算符(.)和箭头运算符(->)都可以用于访问成员,其中点运算获取类对象的一个成员;箭头运算符和点运算符相关(ptr->mem等价于(*ptr).mem)例如:

string s1 = "a string", *p = &s1;
auto = s1.size();
n = (*p).size();                 // 运行p所指对象的size()成员     (1)
n = p->size();                   // 等价于(*p).size()

点运算符的优先级高于解引用运算符,所以执行解引用的子表达式需要加括号,否则代码(1)含义为:

*p.size();          // 错误! p是一个指针,其没有size()成员函数
4.7 条件运算符

条件运算符(?:)允许我们将简单的if-else逻辑嵌入到单个表达式中,条件运算符按照如下形式表示:

cond ? expr1 : expr2
cond是判断条件的表达式,而expr1和expr2是两个类型相同或可能转换成某个类型的表达式。

其执行过程为:首先判断cond的值,如果为真那么执行expr1,否则执行expr2。例如:

finalgrade = (grade < 60) ? "fail" : "pass";   // grade < 60 那么得到fail,否则得到 pass
嵌套条件运算符

当然允许在条件运算符的内部嵌套另外一个条件运算符(条件表达式可以作为另外一个条件运算符的cond或者expr)例如:

finalgrade = (grade > 90 ) ? "high pass" : (grade < 60 ) ? "fail" : "pass";

在这里(grade > 90 ) ? “high pass” : (grade < 60 )作为cond嵌入到另外一个条件预算符中。当然随着条件运算嵌套层数的增加,代码的可读性会急剧下降,所以层数最好不要超过两三层。

在输出表达式中使用条件运算符

条件运算符的优先级非常低,因此当一条长表达式中嵌套了条件运算符的子表达式时,通常需要在它两端加上括号,下面代码是正确的写法和不写括号得到的错误结果:

cout << ((grade < 60 ) ? "fail" : "pass"); // 输出fail或者pass
cout << (grade < 60 ) ? "fail" : "pass";   // 输出0或者1
cout << grade < 60  ? "fail" : "pass";     // 错误,试图比较cout和60 

作为例子解释下第二条语句,第二条语句等价于:

cout << (grade < 60 );
cout ? "fail" : "pass";  // 根据cout的值来定
4.8 位运算符

位运算符作用于整数类型的运算对象,并把运算对象看成是二进制位的集合,下面的表介绍了主要位运算符的用法:

运算符功能用法
~位求反~ expr
<<左移expr1 << expr2
>>右移expr2 >> expr2
&位与expr & expr
^位异或expr ^ expr
^位或expr

一般来说,如果运算对象是“小整型”,则它的值会自动提升成较大的整数类型,运算对象可以是带符号的类型也可以是无符号的。

如果运算对象是带符号的且它的值是负值,那么位运算符如何处理运算对象的“符号位”依赖于机器,而且此时的左移操作可能还会改变符号位的值,因此是一种未定义的行为

注:关于符号位如何处理没有明确的规定,所以强烈建议仅将位运算符用于处理无符号类型。

  • 移位运算符
    << 和 >> 的内置含义是对其运算对象执行基于二进制位的移动操作。
    首先将左侧运算对象的内容按照右侧对象的要求移动指定位数,然后将经过移动的左侧运算对象的拷贝作为求值结果。需要注意的是,右侧对象的值一定不能为负,而且必须小于结果的位数(否则会产生未定义的行为),移除边界之外的位就被舍弃掉了。
    以下为图片示例:
    在这里插入图片描述
    左移运算符在右侧插入值为0的二进制位;
    对于右侧运算符的行为依赖于作用的运算对象类型,如果是无符号类型,在左侧插入值为0的二进制位;如果为带符号类型,在左侧插入符号位的副本或者值为0的二进制位,如何选择视具体情况来定。
    移位运算符优先级不高不低,介于中间,比算数运算符的优先级低,但比关系运算符、赋值运算符和条件运算符的优先级高。

  • 位求反运算符(~),将运算对象逐位求反后生成的一个新值,将1置0,0置为1,下面为一个例子:
    在这里插入图片描述char类型的运算对象首先提升为int类型,提升时运算对象原来的位保持相互不变,往高位添0。

  • 位与、位或、位异或运算符
    与(&)、或(|)、异或(^)运算符在俩哥哥运算对象上逐位执行相应的逻辑操作:
    在这里插入图片描述对于位与运算符(&):同真为真,其余为假;
    对于位与运算符(|):同假为假,其余为真;
    对于位与运算符(&):一真一假方为真,同真同假皆为假;

注意:不要把位运算符和逻辑运算符弄混,&、|、~为位运算符;&&、||、!为逻辑运算符。

4.9 sizeof运算符

sizeof运算符返回一条表达式或一个类型名字所占的字节数,其所得的只是一个size_t类型的常量表达式。运算符的运算对象有两种表达式:

sizeof(type)

sizeof(expr): 返回的是表达式结果类型的大小

值得一提的是,sizeof并不实际计算其运算对象的值,下面举出一些例子(Sales_data是C++Primer书中的定义一种类型):

Sales_data data, *p;

sizeof(Sales_data);        // 存储 Sales_data 类型的所占空间的大小
sizeof data;               // data所占空间的大小,也即 sizeof(Sales_data)
sizeof p;                  // 指针所占空间的大小
sizeof *p;                 // p所指类型的空间大小,即sizeof(Sales_data)
                  
sizeof data.revenue;       // Sales_data 的 revenue 成员对应类型的大小
sizeof Sales_data::revenue;// 与上一行代码等价

上述代码中比较有意思的是 sizeof *p(由于sizeof和*的运算优先级相同,所以等价于sizeof(*p));因为sizeof不会实际求运算对象的值,所以即使p是一个无效(即未初始化)的指针因为不会有什么影响;同样的,在sizeof运算对象中解引用一个无效的指针仍然是一种安全的行为(因为指针没有真正被使用),sizeof不需要真的解引用指针也能知道它所指对象的类型。

sizeof运算符的结果部分的依赖于起作用的类型:

  • 对char类型或者类型为char的表达式执行sizeof运算,结果为1。
  • 对引用类型执行sizeof运算得到被引用对象所占空间的大小。
  • 对指针执行sizeof运算得到指针本身所占空间的大小。
  • 对解引用指针执行sizeof运算得到指针指向的对象所占空间的大小,指针不需要有效。
  • 对数组执行sizeof运算得到整个数组所占空间的大小(注意,sizeof运算不会把数组转换成指针来处理)。
  • 对string对象或vector对象执行sizeof运算只返回该类型固定部分的大小,不会计算对象中的元素占了多少空间。

由于sizeof可以得到整个数组的大小,所以可以使用它得到数组中元素的个数:

constexpr size_t sz = sizeof(ia)/sizeof(*ia);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值