Skip to content

运算符重载

C++ 中我们可以通过重载运算符,赋予运算符不同含义。具体操作是定义一个函数名为 operator + 运算符 的函数,例子如下:

cpp
/**
 * Copyright 2023 <Hardworking Bee>
 */

#include <iostream>

using std::cin;
using std::cout;

class Point {
  friend const Point operator+(const Point&, const Point&);
  friend std::ostream& operator<<(std::ostream&, const Point&);
  friend std::istream& operator>>(std::istream&, Point&);

 private:
  int x_;
  int y_;

 public:
  Point(int x, int y);
  ~Point();

  const Point operator-(const Point& p) const {
    return Point(x_ - p.x_, y_ - p.y_);
  }

  Point& operator+=(const Point& p) {
    x_ += p.x_;
    y_ += p.y_;
    return *this;
  }

  const Point operator-() const { return Point(-x_, -y_); }

  // 前置 ++
  Point& operator++() {
    ++x_;
    ++y_;
    return *this;
  }

  // 后置 ++
  const Point operator++(int) {
    Point old = *this;
    ++(*this);
    return old;
  }

  void Display() { cout << "x: " << x_ << ", y: " << y_ << '\n'; }
};

Point::Point(int x, int y) : x_(x), y_(y) {}

Point::~Point() {}

const Point operator+(const Point& p1, const Point& p2) {
  return Point(p1.x_ + p2.x_, p1.y_ + p2.y_);
}

std::ostream& operator<<(std::ostream& os, const Point& p) {
  os << "x: " << p.x_ << ", y: " << p.y_;
  return os;
}

std::istream& operator>>(std::istream& is, Point& p) {
  is >> p.x_ >> p.y_;
  return is;
}

int main() {
  Point p1(1, 2);
  Point p2(3, 4);
  Point p3 = p1 + p2;
  p3.Display();

  Point p4 = p1 - p2;
  p4.Display();

  Point p5(5, 6);
  p5 += p1;
  p5.Display();

  Point p6 = -p5;
  p6.Display();

  Point p7(7, 8);
  ++p7;
  p7.Display();

  Point p8(9, 10);
  p8++;
  p8.Display();

  cout << p8 << '\n';

  Point p9(0, 0);
  cin >> p9;
  cout << p9 << '\n';

  return 0;
}

TIP

本质上 Point p3 = p1 + p2; 是调用了 operator+ 函数。

你可以打开反汇编视图查看,会发现有一句类似 call 0x555555555241 <operator+(Point const&, Point const&)> 的调用(请注意,以上代码运行在 WSL 上,可能与你的反汇编视图有所不同)。

当然,这就意味着你可以使用函数调用的方式使用 —— Point p3 = operator+(p1, p2);。不过,一般而言,日常编码中更多使用 Point p3 = p1 + p2; 这种方式。

继承

运算符重载在继承中的用法与其它普通函数类似:

cpp
/**
 * Copyright 2023 <Hardworking Bee>
 */

class Person {
 private:
  int age_;

 public:
  explicit Person(int age) : age_(age) {}
  ~Person() {}

  Person& operator=(const Person& p) {
    age_ = p.age_;
    return *this;
  }
};

class Student : public Person {
 private:
  int score_;

 public:
  Student(int age, int score) : Person(age), score_(score) {}
  ~Student() {}

  Student& operator=(const Student& s) {
    Person::operator=(s);
    score_ = s.score_;
    return *this;
  }
};

int main() {
  Student s1{18, 100};
  Student s2{20, 90};
  s1 = s2;

  return 0;
}

仿函数(函数对象、函数调用)

cpp
/**
 * Copyright 2023 <Hardworking Bee>
 */

#include <iostream>

using std::cout;

class Sum {
 private:
  int x_;
  int y_;

 public:
  int operator()(int x, int y) {
    x_ = x;
    y_ = y;
    return x_ + y_;
  }
};

int main() {
  Sum sum;
  cout << sum(1, 2) << '\n';

  return 0;
}

TIP

你可能很好奇上面的方式与直接在全局定义一个普通函数有什么区别。

cpp
// 如下函数也能执行类似的操作
int sum(int x, int y) {
  return x + y
}
  1. 第一种实际上是在调用成员函数,这意味着我们可以在函数内直接访问私有成员变量,而全局定义的普通函数不能;
  2. 对比普通函数,它作为对象可以利用成员变量保存状态。

References