C++ 自增、自减运算符的重载和性能分析小结

01 ++、--运算符重载函数的格式

自增运算符和自减运算符是有前置和后置之分的,如:

a++ // 后置自增运算符
++a // 前置自增运算符

b-- // 后置自减运算符
--b // 前置自减运算符

为了区分所重载的是前置运算符还是后置运算符,C++规定:

前置运算符作为一元运算符重载,重载为成员函数的格式如下:

T & operator++(); // 前置自增运算符的重载函数,函数参数是空
T & operator--(); // 前置自减运算符的重载函数,函数参数是空

后置运算符作为二元运算符重载,多写一个没用的参数,重载为成员函数的个数如下:

T operator++(int); // 后置自增运算符的重载函数,多一个没用的参数
T operator--(int); // 后置自减运算符的重载函数,多一个没用的参数

02 讨论前置和后置运算符的返回值

前置和后置运算符重载函数如下:

前置运算符重载的成员函数 后置运算符重载的成员函数
T & operator++(); T operator++(int);
T & operator--(); T operator--(int);

注意到区别了吗?那么问题来了:

  • 为什么前置运算符返回的是引用 & ?
  • 为什么后置运算符返回的是普通的对象(临时对象)?

主要是因为为了保持原本 C++ 前置和后置运算符的特性:

前置运算符的特性

int a = 0

// (++a) = 5; 可以拆解成:
// a = a + 1;
// a = 5;
(++a) = 5; // 前置++

a 先自增 +1 后, a 的值就为 1 ,然后再参与 a=5 的运算,所以最后 a 的值是 5。

这说明 (++a) 返回的是自增后 a 变量, a 变量在后续运算过程中,a 变量的值会被修改。所以前置运算符的重载函数的返回值必须是引用 &。

  • 后置运算符的特性

而后置运算符,是不能作为左值的,也就是 (a++) = 5; 是不成立的,所以后置运算符的重载函数的返回值就是普通的对象。

03 ++、--运算符重载函数的编写

int main()
{
  CDemo d(10);
  cout << d++ << ","; // 等价于 d.operator++(0);
  cout << d << ","; 

  cout << ++d << ","; // 等价于 d.operator++();
  cout << d << ",";

  cout << d-- << ","; // 等价于 d.operator--(0);
  cout << d << ",";

  cout << --d << ","; // 等价于 d.operator--();
  cout << d << endl;

  return 0;
}

输出结果:

10,11,12,12
12,11,10,10

假设要实现如上的 main 函数输出的结果,该如何编写呢?

首先我们先定义好 CDemo 类,同时也把自增、自减运算符重载函数定义好。

class CDemo
{
public:
  CDemo(int i = 0):m_num(i) {} // 构造函数

  CDemo & operator++();  // 前置自增运算符重载
  CDemo operator++(int); // 后置自增运算符重载

  CDemo & operator--();  // 前置自减运算符重载
  CDemo operator--(int);  // 后置自减运算符重载

private:
  int m_num; // 成员变量
};

接着继续实现前置自增、自减运算符重载函数:

// 前置++
CDemo & CDemo::operator++()
{
  ++m_num;
  return *this;
}

// 前置--
CDemo & CDemo::operator--()
{
  --m_num;
  return *this;
}

后置自增、自减运算符重载,就有点不同,例如后置++,是先参与运算,再进行自增,所以返回值是没自增前的对象,具体实现如下:

// 后置++
CDemo CDemo::operator++(int)
{
  CDemo tmp(*this); // 记录修改前的对象
  m_num--;
  return tmp;    // 返回修改前的对象
}

// 后置--
CDemo CDemo::operator--(int)
{
  CDemo tmp(*this); // 记录修改前的对象
  m_num++;
  return tmp;    // 返回修改前的对象
}

04 前置和后置运算符的性能比较

从上面的例子,我们看到后置运算符的重载函数的执行步骤:

  1. 先要产生一个临时对象来保存未自增或自减前的对象;
  2. 接着成员变量自增或自减;
  3. 最后返回修改前的对象;

而前置运算符的重载函数的执行步骤:

  1. 成员变量自增或自减;
  2. 返回对象引用;

可见,前置运算符的重载函数是比后置运算符的重载函数性能是更高的,开销相对比较少。

当然对于普通变量类型,如int、double、long等,前置和后置是性能差距是不大的。重要是我们在对于对象和迭代器使用自增或自减时,最好用前置的运算符的方式,这样可以减少开销。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 浅谈C++类型转化(运算符重载函数)和基本运算符重载(自增自减)

    类型转化(运算符重载函数) 用转换构造函数可以将一个指定类型的数据转换为类的对象.但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个Complex类对象转换成double类型数据).在C++提供类型转换函数(type conversion function)来解决这个问题.类型转换函数的作用是将一个类的对象转换成另一类型的数据. 类型转换函数的一般形式为: operator 类型名( ){ 实现转换的语句 } 下面是简单实现.这时候,Base起了两方面的作用:类和数据类型.系统会在

  • C++ 自增、自减运算符的重载和性能分析小结

    01 ++.--运算符重载函数的格式 自增运算符和自减运算符是有前置和后置之分的,如: a++ // 后置自增运算符 ++a // 前置自增运算符 b-- // 后置自减运算符 --b // 前置自减运算符 为了区分所重载的是前置运算符还是后置运算符,C++规定: 前置运算符作为一元运算符重载,重载为成员函数的格式如下: T & operator++(); // 前置自增运算符的重载函数,函数参数是空 T & operator--(); // 前置自减运算符的重载函数,函数参数是空 后置运

  • 详解C++ 重载运算符和重载函数

    C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载. 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同. 当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义.选择最合适的重载函数或重载运算符的过程,称为重载决策. C++ 中的函数重载 在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数.类型或

  • C语言 自增自减运算的区别详解及实例

    自增自减 ++自增运算符:如a++,++a都等价于a = a + 1: –自减运算符:如a–,–a都等价于 a = a -1: ++a和a++的区别 虽然++a和a++等价的结果一样,但是运算过程不同,a++ 是先使用a的值,然后再对a做加1处理,++a是先对a作加1处理,然后再使用a的值. 例子 #include <stdio.h> int main() { //int m = 10, n1, n2; //n1 = m++;先将m的值赋给n1,然后m再做自增运算,所以此时,n1=10,m=1

  • 详解C++中的函数调用和下标以及成员访问运算符的重载

    函数调用 使用括号调用的函数调用运算符是二元运算符. 语法 primary-expression ( expression-list ) 备注 在此上下文中,primary-expression 为第一个操作数,并且 expression-list(可能为参数的空列表)为第二个操作数.函数调用运算符用于需要大量参数的操作.这之所以有效,是因为 expression-list 是列表而非单一操作数.函数调用运算符必须是非静态成员函数. 函数调用运算符在重载时不会修改函数的调用方式:相反,它会在运算

  • VBS教程:运算符-减运算符 (-)

    减运算符 (-)计算两个数值的差或表示数值表达式的负值. 语法 1result = number1-number2 语法 2-number 参数result 任意数值变量. number 任意数值表达式. number1 任意数值表达式. number2 任意数值表达式. 说明在语法 1 中,- 运算符是用于计算两个数值差值的算术减法运算符.在语法 2 中,- 运算符用作单目求反运算符,表示表达式的负数. 如果一个或两个表达式都是 Null 表达式,则 result 为 Null.如果某个表达式

  • python列表每个元素同增同减和列表元素去空格的实例

    如下所示: import os var = [1, 2, 3] data = [x*2 for x in var] print (data) two = [[i, i**2] for i in var] print (two) three = [[i, i+i, i**3] for i in var] print (three) fruit = [' banana', ' loganberry ', 'passion fruit '] strip_fruit = [one.strip() for

  • C++ 流插入和流提取运算符的重载的实现

    01 流插入<<运算符的重载 C++ 在输出内容时,最常用的方式: std::cout << 1 <<"hello"; 问题: 那这条语句为什么能成立呢? cout 是什么?"<<" 运算符能用在 cout 上呢? 原因: 实际上,cout 是在 iostream 头文件中定义的 ostream 类的对象. "<<" 能够用在 cout 上是因为,在 ostream 类对 "&

  • C语言运算符的重载详解

    目录 写一个Add函数 为什么不用加号作为函数名 运算符的重载 上面问题解决 总结 写一个Add函数 我们先讨论下面代码,并复习前面的内容 class Complex { private: double Real, Image; public: Complex() :Real(0), Image(0) {} Complex(double r, double i) :Real(r), Image(i) {} ~Complex() {} //Complex Add(const Complex* co

  • MySQL字段自增自减的SQL语句示例介绍

    MySQL的自增语句大家应该都很熟悉 也很简单 复制代码 代码如下: update `info` set `comments` = `comments`+1 WHERE `id` = 32 这样就可以了,但是有时候我们会涉及到做减法, 例如:文章的评论数,在删除或者锁定了一条评论之后需要对该文章总评论数减一 comments smallint(5) unsigned 文章评论总数统计字段 无符号即 0 ~ 65535 之间的数值 1. 通常情况下是可以类似上面自增的方法 把 +号 改成 -号 就

随机推荐