C++:++和--运算符的前置后置如何实现

++和–运算符的前置后置如何实现

可前置可后置的运算符
(1)int a = 5; a++; ++a;结果不同
(2)重载++和–有无意义

如何重载++和–
(1)按最底层规则分析
a++; a是this,other是空的,a是返回值,附带操作是a+1,对应 Type& operator++(void);
++a; this是空的,a是other,a+1是返回值,附带操作是a+1,对应 Type& operator++(const Tpye& other);
(2)代码实战和验证
实践验证编译不通过,报错:coordinate& coordinate::operator++(const coordinate&)’ must take ‘int’ as its argumen
(3)再次分析,因为编译器强制要求++a的重载函数必须携带int类型的参数
Type& operator++(int x);
编译器的理解是:++a时,a是this,other是空的,int x用来做区分,a+1是返回值,附带操作是a+1
实践验证:对应结论刚好是反的。
(4)再次分析
C++编译器认为,a++; 对应Type& operator++(int x); 而++a对应Type& operator++(void);
咱们其他分析包括代码编写都是ok的

#include <iostream>

class Counter {
 private:
  int count;

 public:
  // 构造函数
  Counter(int c = 0) : count(c) {}

  // 重载前置++运算符
  Counter &operator++() {
    ++count;
    return *this;
  }

  // 重载后置++运算符
  Counter operator++(int) {//error: no ‘operator++(int)’ declared for pos
    Counter temp = *this;
    ++count;
    return temp;
  }

  // 重载前置--运算符
  Counter &operator--() {
    --count;
    return *this;
  }

  // 重载后置--运算符
  Counter operator--(int) {
    Counter temp = *this;
    --count;
    return temp;
  }

  // 获取当前计数值
  int getCount() const { return count; }

  // 输出当前计数值
  void print() const { std::cout << "Count: " << count << std::endl; }

  // 友元函数,用于重载<<运算符
  friend std::ostream &operator<<(std::ostream &os, const Counter &c);
};

// 重载<<运算符
std::ostream &operator<<(std::ostream &os, const Counter &c) {
  os << c.count;
  return os;
}

int test070302() {
  // 展示前置和后置的区别
  Counter b(10);
  std::cout << "Initial value of b: " << b << std::endl;
  Counter c = ++b;
  std::cout << "c = ++b: " << c << std::endl;
  std::cout << "Value after ++b: " << b << std::endl;

  Counter d = b++;
  std::cout << "d = b++: " << d << std::endl;
  std::cout << "Value after  b++: " << b << std::endl;

  Counter e = b--;
  std::cout << "e = b--: " << e << std::endl;
  std::cout << "Value after  b--: " << b << std::endl;

  Counter f = --b;
  std::cout << "f = --b: " << f << std::endl;
  std::cout << "Value after  --b: " << b << std::endl;



  return 0;
}

两种运算符重载方法

并非所有运算符都支持重载
(1)下面是不可重载的运算符列表
. 成员访问运算符
., -> 成员指针访问运算符
:: 域运算符
sizeof 长度运算符
? : 条件运算符

预处理符号

并非只有一种方式实现重载
(1)有两种方法可以使运算符重载
第一种:使重载运算符成为该类的成员函数。这允许运算符函数访问类的私有成员。它也允许函数使用隐式的this指针形参来访问调用对象。
第二种:使重载的成员函数成为独立分开的函数。当以这种方式重载时,运算符函数必须声明为类的友元才能访问类的私有成员。

#include <iostream>

class Counter {
 private:
  int count;

 public:
  // 构造函数
  Counter(int c = 0) : count(c) {}

  // 重载前置++运算符
  Counter &operator++() {
    ++count;
    return *this;
  }

  // 重载后置++运算符
  Counter operator++(int) {//error: no ‘operator++(int)’ declared for pos
    Counter temp = *this;
    ++count;
    return temp;
  }

  // 重载前置--运算符
  Counter &operator--() {
    --count;
    return *this;
  }

  // 重载后置--运算符
  Counter operator--(int) {
    Counter temp = *this;
    --count;
    return temp;
  }

  // 获取当前计数值
  int getCount() const { return count; }

  // 输出当前计数值
  void print() const { std::cout << "Count: " << count << std::endl; }

  // 友元函数,用于重载<<运算符
  //在 Counter 类中声明一个友元函数,用于重载 << 运算符
  friend std::ostream &operator<<(std::ostream &os, const Counter &c);
};
//使用友元函数来重载 << 运算符,
//可以使 std::ostream 的输出操作符符合常见的使用方式,
//并且能够直接访问类的私有成员。虽然可以将其实现为成员函数,
//但这会使使用方式不够自然,并且不符合 << 运算符的常见用法
// 重载<<运算符
std::ostream &operator<<(std::ostream &os, const Counter &c) {
  os << c.count;
  return os;
}

int test070302() {
  // 展示前置和后置的区别
  Counter b(10);
  std::cout << "Initial value of b: " << b << std::endl;
  Counter c = ++b;
  std::cout << "c = ++b: " << c << std::endl;
  std::cout << "Value after ++b: " << b << std::endl;

  Counter d = b++;
  std::cout << "d = b++: " << d << std::endl;
  std::cout << "Value after  b++: " << b << std::endl;

  Counter e = b--;
  std::cout << "e = b--: " << e << std::endl;
  std::cout << "Value after  b--: " << b << std::endl;

  Counter f = --b;
  std::cout << "f = --b: " << f << std::endl;
  std::cout << "Value after  --b: " << b << std::endl;

  return 0;
}

如何选择两种运算符重载
(1)大多数运算符(如+ =等)既可以作为成员函数也可以作为独立函数重载。
(2)更好的做法是将二元运算符重载为釆用相同类型形参的独立函数。这是因为,与独立运算符的重载不同,成员函数的重载通过使左侧形参变成隐式的,造成了两个形参之间的人为区别,这将允许转换构造函数应用右侧形参,但不应用左侧形参,从而产生了更改形参顺序的情况,导致正确的程序如果换个方式却出现了编译器错误。示例如下:
Length a(4, 2), c(0);
c = a + 2; //编译,当于 c = a.operator+(2)
c = 2 + a; //不能编译:相当于 c = 2.operator+(a);

总结

a++ ,先加后用,
++a ,先加后用,
后置++ 需要带参数
理解有两种运算符重载的方法,区分什么时候怎么使用

学习记录,侵权联系删除。
来源:朱老师物联网大课堂

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

li星野

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

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

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

打赏作者

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

抵扣说明:

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

余额充值