自增(increment)、自减(decrement)操作符前缀形式与后缀形式的区别_cpu中的increment什么意思-程序员宅基地

技术标签: 转载  扩展  算法  C++  语言  编译器  c  class  

转自侯捷翻译的《more effective c++》中文版

很久以前(八十年代),没有办法区分++和--操作符的前缀与后缀调用。这个问题遭到程序员的报怨,于是C++语言得到了扩展,允许重载increment 和 decrement操作符的两种形式。

    然而有一个句法上的问题,重载函数间的区别决定于它们的参数类型上的差异,但是不论是increment或decrement的前缀还是后缀都只有一个参数。为了解决这个语言问题,C++规定后缀形式有一个int类型参数,当函数被调用时,编译器传递一个0做为int参数的值给该函数:

class UPInt {                     // "unlimited precision int"

public:

  UPInt& operator++();            // ++ 前缀

  const UPInt operator++(int);    // ++ 后缀 

  UPInt& operator--();            // -- 前缀

  const UPInt operator--(int);    // -- 后缀 

  UPInt& operator+=(int);         // += 操作符,UPInts

                                  // 与ints 相运算

  ...

};

UPInt i;

++i;        // 调用 i.operator++();

i++;        // 调用 i.operator++(0);

--i;        // 调用 i.operator--();

i--;        // 调用 i.operator--(0);

这个规则有一些古怪,不过你会习惯的。而尤其要注意的是:这些操作符前缀与后缀形式返回值类型是不同的。前缀形式返回一个引用,后缀形式返回一个const类型。下面我们将讨论++操作符的前缀与后缀形式,这些说明也同样适用于--操作符。

    从你开始做C程序员那天开始,你就记住increment的前缀形式有时叫做“增加然后取回”,后缀形式叫做“取回然后增加”。这两句话非常重要,因为它们是increment前缀与后缀的形式上的规范。

// 前缀形式:增加然后取回值
UPInt& UPInt::operator++()
{
  *this += 1;       // 增加
  return *this;     // 取回值
}
// postfix form: fetch and increment
const UPInt UPInt::operator++(int)
{
  UPInt oldValue = *this;         // 取回值
  ++(*this);                      // 增加
  return oldValue;                // 返回被取回的值
} 

后缀操作符函数没有使用它的参数。它的参数只是用来区分前缀与后缀函数调用。如果你没有在函数里使用参数,许多编译器会显示警告信息,很令人讨厌。为了避免这些警告信息,一种经常使用的方法时省略掉你不想使用的参数名称;如上所示。

    很明显一个后缀increment必须返回一个对象(它返回的是增加前的值),但是为什么是const对象呢?假设不是const对象,下面的代码就是正确的:

UPInt i;
i++++;     // 两次increment后缀

这组代码与下面的代码相同:

i.operator++(0).operator++(0);

很明显,第一个调用的operator++函数返回的对象调用了第二个operator++函数。

    有两个理由导致我们应该厌恶上述这种做法,第一是与内置类型行为不一致。当设计一个类遇到问题时,一个好的准则是使该类的行为与int类型一致。而int类型不允许连续进行两次后缀increment:

int i;
i++++;    // 错误!

 

第二个原因是使用两次后缀increment所产生的结果与调用者期望的不一致。如上所示,第二次调用operator++改变的值是第一次调用返回对象的值,而不是原始对象的值。因此如果:

i++++;

    是合法的,i将仅仅增加了一次。这与人的直觉相违背,使人迷惑(对于int类型和UPInt都是一样),所以最好禁止这么做。

    C++禁止int类型这么做,同时你也必须禁止你自己写的类有这样的行为。最容易的方法是让后缀increment 返回const对象。当编译器遇到这样的代码:

i++++;         // same as 
i.operator++(0).operator++(0);

 

它发现从第一个operator++函数返回的const对象又调用operator++函数,然而这个函数是一个non-const成员函数,所以const对象不能调用这个函数。如果你原来想过让一个函数返回const对象没有任何意义,现在你就知道有时还是有用的,后缀increment和decrement就是例子。(更多的例子参见Effective C++ 条款21)

    如果你很关心效率问题,当你第一次看到后缀increment函数时,你可能觉得有些问题。这个函数必须建立一个临时对象以做为它的返回值,(参见条款M19),上述实现代码建立了一个显示的临时对象(oldValue),这个临时对象必须被构造并在最后被析构。前缀increment函数没有这样的临时对象。由此得出一个令人惊讶的结论,如果仅为了提高代码效率,UPInt的调用者应该尽量使用前缀increment,少用后缀increment,除非确实需要使用后缀increment。让我们明确一下,当处理用户定义的类型时,尽可能地使用前缀increment,因为它的效率较高。

    我们再观察一下后缀与前缀increment操作符。它们除了返回值不同外,所完成的功能是一样的,即值加一。简而言之,它们被认为功能一样。那么你如何确保后缀increment和前缀increment的行为一致呢?当不同的程序员去维护和升级代码时,有什么能保证它们不会产生差异?除非你遵守上述代码里的原则,这才能得到确保。这个原则是后缀increment和decrement应该根据它们的前缀形式来实现。你仅仅需要维护前缀版本,因为后缀形式自动与前缀形式的行为一致。

    正如你所看到的,掌握前缀和后缀increment和decrement是容易的。一旦了解了他们正确的返回值类型以及后缀操作符应该以前缀操作符为基础来实现的规则,就足够了。

 

T& operator++() // ++i
{
    ++i;
    return i;
}

const T& operator++(int) // i++
{
    temp = i;
    ++i;
    return temp;
}


 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ManniEmma/article/details/7822265

智能推荐

hdoj Be the Winner 2509 (NIM博弈)_hduojbe the winner-程序员宅基地

文章浏览阅读326次。Be the WinnerTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2713 Accepted Submission(s): 1484Problem DescriptionLet's consider m_hduojbe the winner

unity 手游虚拟摇杆代码参考-程序员宅基地

文章浏览阅读3.2k次。手游 摇杆_摇杆代码

memlock过低导致的数据库性能问题(r6笔记第10天)-程序员宅基地

文章浏览阅读824次。今天在一台备库机器上准备搭建active data guard ,在主库上做配置的时候,发现主库的反应有些慢,主要的感觉就是敲命令的时候似乎都有些停顿。带着疑问查看了下数..._memlock limit is less than 64mb

推荐几本shell学习的书 (r9笔记第98天)-程序员宅基地

文章浏览阅读180次。周末整理了一下书架,一来书架上实在是放不下东西了,四层书架,两层在闺女的触及范围之内,所以直接拿胶带封住,留下两层勉强可用。二来书架已经不是放书的地儿,生活用品已..._shell 书籍 推荐 杨建荣

PE文件格式_pe工具的文件扩展名-程序员宅基地

文章浏览阅读1.2k次。PE文件格式分析及修改(图)12009-01-09 14:08PE 的意思是 Portable Executable(可移植的执行体)。它是 Win32环境自身所带的执行文件格式。它的一些特性继承自Unix的Coff(common object file format)文件格式。“Portable Executable”(可移植的执行体)意味着此文件格式是跨Win32平台的_pe工具的文件扩展名

Bluetooth MESH探究 --- (7) BLE core spec之为什么BLE能有更低功耗_ble 为什么功耗低-程序员宅基地

文章浏览阅读3.6k次。BLE与其它蓝牙协议最典型的区别就是BLE是专门为低功耗、低复杂度以及低成本设备设计。那么,BLE是通过什么方法做到更多功耗的呢? 对于蓝牙设备甚至可以说对于所有无线通信设备来说,最大的功耗就来自于射频电路部分。比如,对于TI CC2540芯片来说,RF处于接收状态的电流为19.6mA,RF处于发射状态的电流为24mA,而RF处于sleep状态的电流仅为0.9uA。所以,如果能够最大限度地_ble 为什么功耗低

随便推点

纳什博弈论-程序员宅基地

文章浏览阅读1.5k次。纳什博弈论的原理与应用   1950年和1951年纳什的两篇关于非合作博弈论的重要论文,彻底改变了人们对竞争和市场的看法。他证明了非合作博弈及其均衡解,并证明了均衡解的存在性,即著名的纳什均衡。从而揭示了博弈均衡与经济均衡的内在联系。纳什的研究奠定了现代非合作博弈论的基石,后来的博弈论研究基本上都沿着这条主线展开的。然而,纳什天才的发现却遭到冯·诺依曼的断然否定,在此之前他还受到爱因斯坦的冷遇。但是骨子里挑战权威、藐视权威的本性,使纳什坚持了自己的观点,终成一代大师。要不是30多年的严重精神病折_纳什博弈论

ios注意事项-程序员宅基地

文章浏览阅读177次。1.tableview顶部留白问题当cell的类型是plaint类型时,直接设置self.automaticallyAdjustsScrollViewInsets=NO;应该就可以的当cell的类型是group类型时,此时要去掉tableView顶部的空白需要两步:1.设置tableView的tableHeaderView高度为0.5;self.MenuTable.tableHea

数据结构——不带头节点的单链表_不带图节点的单链表类的成员函数-程序员宅基地

文章浏览阅读403次。作者:小琛欢迎转载,请标明出处单链表的概念概念:**链表是一种物理存储结构上非连续、非顺序,逻辑上连续的结构。**是通过链表中的指针链 接次序实现的。如下图:单链表的实现鉴于后续的面试和oj题目类型,这里实现不带头节点的单链表Plist.h#ifndef _LIST_H__#define _LIST_H__#include <stdio.h>#include &l..._不带图节点的单链表类的成员函数

Cento7配置网络及代理_centos7网卡不支持代理-程序员宅基地

文章浏览阅读528次。1、配置网络编辑网卡配置文件[root@localhost yum.repos.d]# vim /etc/sysconfig/network-scripts/ifcfg-eno16777736TYPE=EthernetBOOTPROTO=noneDEFROUTE=yesIPV4_FAILURE_FATAL=noIPV6INIT=yesIPV6_AUTOCONF=yesIPV6_..._centos7网卡不支持代理

input输入框赋值、取值_input框赋值取值-程序员宅基地

文章浏览阅读3.9k次。目录htmleasyuilayui自己做个记录,在对页面进行修改,开发的时候,总是去查资料html<input id="cpno" name="cpno" value="" />js: 赋值: $('#cpno').val( "CSDN有限公司"); -------方式1 $('#cpno').val("setValue", "CSDN有限公司"); -------方式..._input框赋值取值

如何有效预防CC攻击?_怎么防止被c&c攻击-程序员宅基地

文章浏览阅读348次。CC攻击也是属于流量型攻击中的一种,大部分的高防机房,是可以承受住大量的DDOS攻击的,这些防护主要来源于硬防。CC攻击可以算的上是DDOS攻击的一个升级版,如果想要抵御CC攻击可没有抵御DDOS攻击那么简单,单靠硬防还是不够的,必须要配合人工进行策略调控才可以防御住。CC攻击基本上都是针对端口的攻击,所以网站遇到CC攻击的几率会更大一些。在攻击模式上与一般的流量型攻击是差不多的,主要是通过伪装成正常的用户不停的对网站进行访问,从而导致服务器资源耗尽,无法正常的被访问。那么我们应该怎么去预防CC攻击呢?_怎么防止被c&c攻击

推荐文章

热门文章

相关标签