Skip to content

Ch 22: 运算符重载

  • 深入理解运算符重载的概念和设计原则
  • 掌握成员运算符和友元运算符的选择
  • 学会实现各种常见运算符(算术、比较、下标等)
  • 理解 C++20 三路比较运算符 <=>
  • 掌握类型转换运算符的使用
# Python - 通过特殊方法重载运算符
class Vec2:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vec2(self.x + other.x, self.y + other.y)
def __repr__(self):
return f"Vec2({self.x}, {self.y})"
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __mul__(self, scalar):
return Vec2(self.x * scalar, self.y * scalar)
def __rmul__(self, scalar):
return Vec2(self.x * scalar, self.y * scalar)
v1 = Vec2(1, 2)
v2 = Vec2(3, 4)
print(v1 + v2) # Vec2(4, 6)
print(v1 * 3) # Vec2(3, 6)
print(2 * v1) # Vec2(2, 4) - 调用 __rmul__
print(v1 == Vec2(1, 2)) # True
# 常用运算符方法
__add__ # +
__sub__ # -
__mul__ # *
__truediv__ # /
__floordiv__ # //
__mod__ # %
__pow__ # **
__and__ # &
__or__ # |
__xor__ # ^
__lt__ # <
__le__ # <=
__gt__ # >
__ge__ # >=
__eq__ # ==
__ne__ # !=
__getitem__ # []
__setitem__ # [] =
__call__ # ()
__len__ # len()
__iter__ # iter()
#include <iostream>
#include <string>
class Vec2 {
public:
Vec2(double x, double y) : x_(x), y_(y) {}
// 成员运算符:+=
Vec2& operator+=(const Vec2& other) {
x_ += other.x_;
y_ += other.y_;
return *this;
}
// 成员运算符:+
Vec2 operator+(const Vec2& other) const {
return Vec2(x_ + other.x_, y_ + other.y_);
}
// 成员运算符:- *
Vec2 operator-(const Vec2& other) const {
return Vec2(x_ - other.x_, y_ - other.y_);
}
Vec2 operator*(double scalar) const {
return Vec2(x_ * scalar, y_ * scalar);
}
// 比较运算符
bool operator==(const Vec2& other) const {
return x_ == other.x_ && y_ == other.y_;
}
bool operator!=(const Vec2& other) const {
return !(*this == other);
}
// 友元声明 - 用于 << 运算符
friend std::ostream& operator<<(std::ostream& os, const Vec2& v);
private:
double x_;
double y_;
};
// 友元函数实现
std::ostream& operator<<(std::ostream& os, const Vec2& v) {
return os << "Vec2(" << v.x_ << ", " << v.y_ << ")";
}
// 非成员运算符:scalar * Vec2
Vec2 operator*(double scalar, const Vec2& v) {
return v * scalar; // 利用已有的成员运算符
}
int main() {
Vec2 v1(1, 2), v2(3, 4);
std::cout << "v1 = " << v1 << "\n"; // Vec2(1, 2)
std::cout << "v2 = " << v2 << "\n"; // Vec2(3, 4)
std::cout << "v1 + v2 = " << (v1 + v2) << "\n"; // Vec2(4, 6)
std::cout << "v2 - v1 = " << (v2 - v1) << "\n"; // Vec2(2, 2)
std::cout << "v1 * 3 = " << (v1 * 3) << "\n"; // Vec2(3, 6)
std::cout << "2 * v2 = " << (2 * v2) << "\n"; // Vec2(6, 8)
std::cout << "v1 == v1: " << std::boolalpha << (v1 == v1) << "\n";
std::cout << "v1 == v2: " << (v1 == v2) << "\n";
return 0;
}
运算符类型推荐方式原因
a op b(两边同类)成员或友元对称
a op b(左边不是此类)友元/非成员需要左操作数
a += b成员修改左操作数
a == b成员或友元对称
// ❌ 错误:v1 + 5 可能编译,但 5 + v1 不行
class Vec2 {
Vec2 operator+(double scalar) { /* ... */ }
};
// ✅ 正确:同时支持两种
class Vec2 {
Vec2 operator+(double scalar) const { /* ... */ }
};
friend Vec2 operator+(double, const Vec2&); // 左操作数不是此类
// 调用
v1 + 5; // v1.operator+(5)
5 + v1; // operator+(5, v1)
#include <iostream>
#include <cmath>
class Complex {
public:
Complex(double real, double imag) : real_(real), imag_(imag) {}
// 一元负号
Complex operator-() const {
return Complex(-real_, -imag_);
}
// 一元正号(通常只是返回拷贝)
Complex operator+() const {
return *this;
}
// 前置递增
Complex& operator++() {
++real_;
return *this;
}
// 后置递增(int 参数区分)
Complex operator++(int) {
Complex temp(*this);
++real_;
return temp;
}
double real() const { return real_; }
double imag() const { return imag_; }
private:
double real_;
double imag_;
};
int main() {
Complex c(3, 4);
Complex neg = -c; // (-3, -4)
Complex pos = +c; // (3, 4)
++c; // (4, 4)
c++; // (5, 4)
return 0;
}
#include <string>
class String {
public:
explicit String(const std::string& s) : data_(s) {}
// 字符串连接
String operator+(const String& other) const {
return String(data_ + other.data_);
}
// 字符串比较
bool operator==(const String& other) const {
return data_ == other.data_;
}
bool operator<(const String& other) const {
return data_ < other.data_;
}
std::string get() const { return data_; }
private:
std::string data_;
};
// 支持 String + const char*
String operator+(const String& lhs, const char* rhs) {
return lhs + String(rhs);
}
// 支持 const char* + String
String operator+(const char* lhs, const String& rhs) {
return String(lhs) + rhs;
}
int main() {
String s1("Hello");
String s2(" World");
auto s3 = s1 + s2; // Hello World
auto s4 = s1 + "!"; // Hello!
auto s5 = "Hi, " + s1; // Hi, Hello
return 0;
}
class Vec2 {
public:
Vec2& operator+=(const Vec2& other) {
x_ += other.x_;
y_ += other.y_;
return *this;
}
Vec2& operator-=(const Vec2& other) {
x_ -= other.x_;
y_ -= other.y_;
return *this;
}
Vec2& operator*=(double scalar) {
x_ *= scalar;
y_ *= scalar;
return *this;
}
Vec2& operator/=(double scalar) {
x_ /= scalar;
y_ /= scalar;
return *this;
}
// 基于 += 实现 +
Vec2 operator+(const Vec2& other) const {
Vec2 result(*this);
result += other;
return result;
}
private:
double x_, y_;
};
#include <string>
class Person {
public:
Person(const std::string& name, int age) : name_(name), age_(age) {}
bool operator==(const Person& other) const {
return name_ == other.name_ && age_ == other.age_;
}
bool operator!=(const Person& other) const {
return !(*this == other);
}
bool operator<(const Person& other) const {
return name_ < other.name_ ||
(name_ == other.name_ && age_ < other.age_);
}
bool operator<=(const Person& other) const {
return !(other < *this);
}
bool operator>(const Person& other) const {
return other < *this;
}
bool operator>=(const Person& other) const {
return !(*this < other);
}
private:
std::string name_;
int age_;
};
#include <compare>
#include <iostream>
class Point {
public:
Point(int x, int y) : x_(x), y_(y) {}
// C++20:自动生成所有比较运算符
auto operator<=>(const Point& other) const = default;
// 或者自定义顺序
auto operator<=>(const Point& other) const {
if (auto cmp = x_ <=> other.x_; cmp != 0) return cmp;
return y_ <=> other.y_;
}
private:
int x_;
int y_;
};
int main() {
Point p1(1, 2);
Point p2(1, 2);
Point p3(2, 1);
// C++20 比较结果
std::cout << std::boolalpha;
std::cout << "p1 == p2: " << (p1 == p2) << "\n"; // true
std::cout << "p1 < p3: " << (p1 < p3) << "\n"; // true
std::cout << "p1 <= p2: " << (p1 <= p2) << "\n"; // true
std::cout << "p1 > p3: " << (p1 > p3) << "\n"; // false
// spaceship 运算符返回 std::strong_ordering
auto result = p1 <=> p3;
if (result < 0) {
std::cout << "p1 < p3\n";
} else if (result > 0) {
std::cout << "p1 > p3\n";
} else {
std::cout << "p1 == p3\n";
}
return 0;
}
#include <compare>
#include <string>
#include <iostream>
class Person {
public:
Person(const std::string& name, int age) : name_(name), age_(age) {}
// 按年龄排序,但同年龄按姓名
auto operator<=>(const Person& other) const {
if (auto cmp = age_ <=> other.age_; cmp != 0) return cmp;
return name_ <=> other.name_;
}
private:
std::string name_;
int age_;
};
int main() {
Person p1("Alice", 30);
Person p2("Bob", 25);
Person p3("Alice", 25);
std::cout << "p1 < p2: " << (p1 < p2) << "\n"; // true(Bob 更年轻)
std::cout << "p2 < p3: " << (p2 < p3) << "\n"; // true(同名,Alice 更年轻)
std::cout << "p1 > p2: " << (p1 > p2) << "\n"; // false
return 0;
}
#include <vector>
#include <stdexcept>
class Matrix {
public:
Matrix(std::size_t rows, std::size_t cols)
: rows_(rows), cols_(cols), data_(rows * cols, 0.0) {}
// 下标访问
double& operator()(std::size_t row, std::size_t col) {
check_bounds(row, col);
return data_[row * cols_ + col];
}
const double& operator()(std::size_t row, std::size_t col) const {
check_bounds(row, col);
return data_[row * cols_ + col];
}
// 一维下标
double& operator[](std::size_t index) {
return data_[index];
}
const double& operator[](std::size_t index) const {
return data_[index];
}
std::size_t rows() const { return rows_; }
std::size_t cols() const { return cols_; }
private:
void check_bounds(std::size_t row, std::size_t col) const {
if (row >= rows_ || col >= cols_) {
throw std::out_of_range("Matrix index out of range");
}
}
std::size_t rows_;
std::size_t cols_;
std::vector<double> data_;
};
int main() {
Matrix m(3, 3);
m(0, 0) = 1.0;
m(1, 1) = 2.0;
m(2, 2) = 3.0;
std::cout << "m(1,1) = " << m(1, 1) << "\n";
// [] 操作
m[0] = 9.0; // 设置第一个元素
return 0;
}
#include <vector>
#include <algorithm>
#include <iostream>
// 函数对象(仿函数)
class Multiply {
public:
explicit Multiply(int factor) : factor_(factor) {}
int operator()(int x) const {
return x * factor_;
}
private:
int factor_;
};
class IsEven {
public:
bool operator()(int x) const {
return x % 2 == 0;
}
};
int main() {
// 函数对象
Multiply by_3(3);
Multiply by_5(5);
std::cout << by_3(10) << "\n"; // 30
std::cout << by_5(10) << "\n"; // 50
// 用于算法
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::transform(numbers.begin(), numbers.end(), numbers.begin(), by_3);
// numbers = {3, 6, 9, 12, 15}
int evens = std::count_if(numbers.begin(), numbers.end(), IsEven());
std::cout << "Evens: " << evens << "\n";
// Lambda 是函数对象的语法糖
auto add_10 = [](int x) { return x + 10; };
std::cout << add_10(5) << "\n"; // 15
return 0;
}
#include <functional>
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> a = {1, 3, 5, 7};
std::vector<int> b = {2, 4, 6, 8};
// 预定义函数对象
std::vector<int> c(4);
// 加法
std::transform(a.begin(), a.end(), b.begin(), c.begin(), std::plus<int>());
// c = {3, 7, 11, 15}
// 乘法
std::transform(a.begin(), a.end(), b.begin(), c.begin(), std::multiplies<int>());
// c = {2, 12, 30, 56}
// 使用 std::bind 绑定参数
auto divide_by_2 = std::bind(std::divides<int>(), std::placeholders::_1, 2);
std::vector<int> d = {1, 2, 3, 4, 5};
std::transform(d.begin(), d.end(), d.begin(), divide_by_2);
// d = {0, 1, 1, 2, 2}
return 0;
}
#include <string>
#include <iostream>
class Fraction {
public:
Fraction(int num, int denom) : num_(num), denom_(denom) {
normalize();
}
void normalize() {
if (denom_ < 0) {
num_ = -num_;
denom_ = -denom_;
}
int g = gcd(std::abs(num_), std::abs(denom_));
num_ /= g;
denom_ /= g;
}
static int gcd(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
// 显式转换为 double
explicit operator double() const {
return static_cast<double>(num_) / denom_;
}
// 隐式转换为 string(不推荐,但有时有用)
operator std::string() const {
return std::to_string(num_) + "/" + std::to_string(denom_);
}
int num() const { return num_; }
int denom() const { return denom_; }
private:
int num_;
int denom_;
};
class BoolFlag {
public:
explicit BoolFlag(bool value) : value_(value) {}
// 转换为 bool
explicit operator bool() const {
return value_;
}
private:
bool value_;
};
int main() {
Fraction f(3, 4);
// 显式转换
double d = static_cast<double>(f); // 0.75
std::cout << "As double: " << d << "\n";
// 隐式转换(如果有非 explicit 的转换运算符)
std::string s = f; // 调用 operator std::string()
std::cout << "As string: " << s << "\n";
// BoolFlag 用于条件判断
BoolFlag flag(true);
if (flag) { // 调用 operator bool()
std::cout << "Flag is true\n";
}
// explicit 防止意外转换
// void process(double x);
// process(f); // ❌ 编译错误!explicit 转换不能隐式调用
return 0;
}
#include <iostream>
#include <string>
class Person {
public:
Person() = default;
Person(const std::string& name, int age) : name_(name), age_(age) {}
// 友元声明
friend std::istream& operator>>(std::istream& is, Person& p);
friend std::ostream& operator<<(std::ostream& os, const Person& p);
private:
std::string name_;
int age_ = 0;
};
std::ostream& operator<<(std::ostream& os, const Person& p) {
return os << "Person{name=" << p.name_ << ", age=" << p.age_ << "}";
}
std::istream& operator>>(std::istream& is, Person& p) {
// 读取格式: "Name,Age"
char comma;
std::string name;
int age;
is >> name >> comma >> age;
if (is) {
p.name_ = name;
p.age_ = age;
}
return is;
}
int main() {
Person p1("Alice", 30);
std::cout << p1 << "\n";
Person p2;
std::cout << "Enter person (name,age): ";
std::cin >> p2;
std::cout << "You entered: " << p2 << "\n";
return 0;
}
#include <iostream>
#include <cmath>
#include <compare>
class Complex {
public:
Complex(double real = 0, double imag = 0)
: real_(real), imag_(imag) {}
// 访问
double real() const { return real_; }
double imag() const { return imag_; }
// 算术运算符
Complex& operator+=(const Complex& other) {
real_ += other.real_;
imag_ += other.imag_;
return *this;
}
Complex& operator-=(const Complex& other) {
real_ -= other.real_;
imag_ -= other.imag_;
return *this;
}
Complex& operator*=(const Complex& other) {
double new_real = real_ * other.real_ - imag_ * other.imag_;
double new_imag = real_ * other.imag_ + imag_ * other.real_;
real_ = new_real;
imag_ = new_imag;
return *this;
}
Complex& operator/=(const Complex& other) {
double denom = other.real_ * other.real_ + other.imag_ * other.imag_;
double new_real = (real_ * other.real_ + imag_ * other.imag_) / denom;
double new_imag = (imag_ * other.real_ - real_ * other.imag_) / denom;
real_ = new_real;
imag_ = new_imag;
return *this;
}
Complex operator+(const Complex& other) const {
Complex result(*this);
result += other;
return result;
}
Complex operator-(const Complex& other) const {
Complex result(*this);
result -= other;
return result;
}
Complex operator*(const Complex& other) const {
Complex result(*this);
result *= other;
return result;
}
Complex operator/(const Complex& other) const {
Complex result(*this);
result /= other;
return result;
}
// 一元运算符
Complex operator-() const {
return Complex(-real_, -imag_);
}
Complex operator+() const {
return *this;
}
// 比较运算符(C++20)
auto operator<=>(const Complex& other) const {
if (auto cmp = real_ <=> other.real_; cmp != 0) return cmp;
return imag_ <=> other.imag_;
}
bool operator==(const Complex& other) const = default;
// 转换
double magnitude() const {
return std::sqrt(real_ * real_ + imag_ * imag_);
}
double phase() const {
return std::atan2(imag_, real_);
}
// 输出
friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << c.real_;
if (c.imag_ >= 0) os << "+";
os << c.imag_ << "i";
return os;
}
private:
double real_;
double imag_;
};
int main() {
Complex a(3, 4);
Complex b(1, -2);
std::cout << "a = " << a << "\n";
std::cout << "b = " << b << "\n";
std::cout << "a + b = " << (a + b) << "\n";
std::cout << "a - b = " << (a - b) << "\n";
std::cout << "a * b = " << (a * b) << "\n";
std::cout << "a / b = " << (a / b) << "\n";
std::cout << "-a = " << (-a) << "\n";
std::cout << "|a| = " << a.magnitude() << "\n";
std::cout << "arg(a) = " << a.phase() << "\n";
return 0;
}
运算符类型常用实现方式
算术 +, -, *, /成员函数,返回新对象
复合赋值 +=, -= 等成员函数,返回 *this
比较 ==, <, >C++20 用 <=> 自动生成
下标 []成员函数,返回引用
输入输出 <<, >>友元函数
类型转换operator T() 或 explicit operator T()
函数调用 ()成员函数(仿函数)

设计原则:

  • 运算符应符合语义(如 + 不应修改左操作数)
  • 对称运算符用友元函数实现
  • 优先实现 += 等复合赋值,再基于它实现 +
  • 用 explicit 防止意外的类型转换
  • C++20 优先使用 <=> 自动生成比较运算符

下章预告:ch23 学习智能指针 unique_ptr、shared_ptr 和 weak_ptr。