====== 第七章 运算符重载 ======
本章将详细介绍C++的运算符重载机制,包括成员函数重载、友元函数重载、类型转换运算符等。
===== 7.1 运算符重载基础 =====
=== 7.1.1 基本概念 ===
运算符重载允许为自定义类型定义运算符的行为,使代码更直观、更自然。
#include
using namespace std;
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 成员函数重载 +
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// 成员函数重载 -
Complex operator-(const Complex& other) const {
return Complex(real - other.real, imag - other.imag);
}
// 成员函数重载 *(复数乘法)
Complex operator*(const Complex& other) const {
return Complex(
real * other.real - imag * other.imag,
real * other.imag + imag * other.real
);
}
// 重载 << 输出运算符(友元函数)
friend ostream& operator<<(ostream& os, const Complex& c) {
os << c.real;
if (c.imag >= 0) os << "+";
os << c.imag << "i";
return os;
}
// 重载 >> 输入运算符(友元函数)
friend istream& operator>>(istream& is, Complex& c) {
is >> c.real >> c.imag;
return is;
}
};
int main() {
Complex c1(3, 4);
Complex c2(1, 2);
Complex c3 = c1 + c2; // 等价于 c1.operator+(c2)
Complex c4 = c1 - c2;
Complex c5 = c1 * c2;
cout << "c1 = " << c1 << endl;
cout << "c2 = " << c2 << endl;
cout << "c1 + c2 = " << c3 << endl; // 4+6i
cout << "c1 - c2 = " << c4 << endl; // 2+2i
cout << "c1 * c2 = " << c5 << endl; // -5+10i
return 0;
}
=== 7.1.2 可重载的运算符 ===
| 运算符类别 | 可重载运算符 |
|-----------|-------------|
| 算术 | +, -, *, /, % |
| 关系 | ==, !=, <, >, <=, >= |
| 逻辑 | !, &&, || |
| 位运算 | ~, &, |, ^, <<, >> |
| 赋值 | =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= |
| 自增/自减 | ++, -- |
| 内存 | new, delete, new[], delete[] |
| 访问 | [], (), ->, ->*, .* |
| 其他 | , (逗号), & (取地址), * (解引用) |
不可重载的运算符:
* ::(作用域解析)
* .(成员访问)
* .*(成员指针访问)
* ?:(三元条件)
* sizeof
* typeid
===== 7.2 成员函数重载 =====
=== 7.2.1 单目运算符重载 ===
#include
using namespace std;
class Counter {
private:
int count;
public:
Counter(int c = 0) : count(c) {}
// 前缀 ++
Counter& operator++() {
++count;
return *this;
}
// 后缀 ++ (int是区分标记)
Counter operator++(int) {
Counter temp(*this);
count++;
return temp;
}
// 前缀 --
Counter& operator--() {
--count;
return *this;
}
// 后缀 --
Counter operator--(int) {
Counter temp(*this);
count--;
return temp;
}
// 一元负号
Counter operator-() const {
return Counter(-count);
}
// 逻辑非
bool operator!() const {
return count == 0;
}
// 友元输出
friend ostream& operator<<(ostream& os, const Counter& c) {
os << c.count;
return os;
}
};
int main() {
Counter c1(5);
cout << "c1 = " << c1 << endl;
cout << "++c1 = " << ++c1 << endl; // 前缀,先增加后返回
cout << "c1++ = " << c1++ << endl; // 后缀,返回原值后增加
cout << "c1 = " << c1 << endl;
Counter c2 = -c1;
cout << "-c1 = " << c2 << endl;
cout << "!c1 = " << !c1 << endl; // false (0)
return 0;
}
=== 7.2.2 赋值运算符重载 ===
#include
#include
using namespace std;
class String {
private:
char* data;
size_t length;
public:
// 构造函数
String(const char* str = "") {
length = strlen(str);
data = new char[length + 1];
strcpy(data, str);
}
// 拷贝构造函数
String(const String& other) {
length = other.length;
data = new char[length + 1];
strcpy(data, other.data);
}
// 拷贝赋值运算符
String& operator=(const String& other) {
// 1. 检查自赋值
if (this != &other) {
// 2. 释放原有资源
delete[] data;
// 3. 复制新资源
length = other.length;
data = new char[length + 1];
strcpy(data, other.data);
}
// 4. 返回自身引用
return *this;
}
// 移动构造函数(C++11)
String(String&& other) noexcept {
data = other.data;
length = other.length;
other.data = nullptr;
other.length = 0;
}
// 移动赋值运算符(C++11)
String& operator=(String&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
length = other.length;
other.data = nullptr;
other.length = 0;
}
return *this;
}
// 析构函数
~String() {
delete[] data;
}
// 友元输出
friend ostream& operator<<(ostream& os, const String& s) {
os << s.data;
return os;
}
};
int main() {
String s1("Hello");
String s2("World");
s2 = s1; // 拷贝赋值
cout << "s2 = " << s2 << endl;
String s3 = s1; // 拷贝构造
// 自赋值
s1 = s1; // 安全,因为有自赋值检查
return 0;
}
=== 7.2.3 下标运算符重载 ===
#include
#include
using namespace std;
class Array {
private:
int* data;
size_t size;
public:
Array(size_t n) : size(n) {
data = new int[n]();
}
// 拷贝构造函数
Array(const Array& other) : size(other.size) {
data = new int[size];
for (size_t i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
// 拷贝赋值
Array& operator=(const Array& other) {
if (this != &other) {
delete[] data;
size = other.size;
data = new int[size];
for (size_t i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
return *this;
}
~Array() {
delete[] data;
}
// 非const版本
int& operator[](size_t index) {
if (index >= size) {
throw out_of_range("Index out of bounds");
}
return data[index];
}
// const版本
const int& operator[](size_t index) const {
if (index >= size) {
throw out_of_range("Index out of bounds");
}
return data[index];
}
size_t getSize() const { return size; }
};
int main() {
Array arr(5);
// 使用下标运算符
for (size_t i = 0; i < arr.getSize(); i++) {
arr[i] = static_cast(i * 10); // 调用非const版本
}
const Array& carr = arr;
for (size_t i = 0; i < carr.getSize(); i++) {
cout << carr[i] << " "; // 调用const版本
}
cout << endl;
// 越界访问会抛出异常
try {
arr[10] = 100;
} catch (const exception& e) {
cout << "Error: " << e.what() << endl;
}
return 0;
}
===== 7.3 友元函数重载 =====
=== 7.3.1 二元运算符的友元重载 ===
#include
using namespace std;
class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 友元函数可以访问私有成员
// 左操作数是double,右操作数是Complex
friend Complex operator+(double lhs, const Complex& rhs) {
return Complex(lhs + rhs.real, rhs.imag);
}
// 对称性:也定义 Complex + double
friend Complex operator+(const Complex& lhs, double rhs) {
return Complex(lhs.real + rhs, lhs.imag);
}
// 两个Complex相加
friend Complex operator+(const Complex& lhs, const Complex& rhs) {
return Complex(lhs.real + rhs.real, lhs.imag + rhs.imag);
}
// 相等比较
friend bool operator==(const Complex& lhs, const Complex& rhs) {
return lhs.real == rhs.real && lhs.imag == rhs.imag;
}
friend bool operator!=(const Complex& lhs, const Complex& rhs) {
return !(lhs == rhs);
}
friend ostream& operator<<(ostream& os, const Complex& c) {
os << c.real;
if (c.imag >= 0) os << "+";
os << c.imag << "i";
return os;
}
};
int main() {
Complex c1(3, 4);
Complex c2(1, 2);
Complex c3 = c1 + c2; // Complex + Complex
Complex c4 = c1 + 5.0; // Complex + double
Complex c5 = 5.0 + c1; // double + Complex (需要友元)
cout << "c1 + c2 = " << c3 << endl;
cout << "c1 + 5 = " << c4 << endl;
cout << "5 + c1 = " << c5 << endl;
cout << "c1 == c2: " << (c1 == c2) << endl;
cout << "c1 != c2: " << (c1 != c2) << endl;
return 0;
}
=== 7.3.2 输入输出运算符重载 ===
#include
#include
using namespace std;
class Date {
private:
int year, month, day;
public:
Date(int y = 2000, int m = 1, int d = 1)
: year(y), month(m), day(d) {}
// 输出运算符
friend ostream& operator<<(ostream& os, const Date& date) {
os << date.year << "-"
<< (date.month < 10 ? "0" : "") << date.month << "-"
<< (date.day < 10 ? "0" : "") << date.day;
return os;
}
// 输入运算符
friend istream& operator>>(istream& is, Date& date) {
char sep;
is >> date.year >> sep >> date.month >> sep >> date.day;
// 简单的验证
if (date.month < 1 || date.month > 12 ||
date.day < 1 || date.day > 31) {
is.setstate(ios::failbit);
}
return is;
}
};
int main() {
Date d1(2024, 6, 15);
cout << "Date: " << d1 << endl;
Date d2;
cout << "Enter date (yyyy-mm-dd): ";
cin >> d2;
if (cin.fail()) {
cout << "Invalid date format!" << endl;
} else {
cout << "You entered: " << d2 << endl;
}
return 0;
}
===== 7.4 函数调用运算符重载 =====
=== 7.4.1 函数对象(Functor) ===
#include
#include
#include
using namespace std;
// 函数对象类
class Multiplier {
private:
int factor;
public:
Multiplier(int f) : factor(f) {}
// 重载函数调用运算符
int operator()(int value) const {
return value * factor;
}
};
// 带状态的函数对象
class Average {
private:
double sum = 0;
int count = 0;
public:
void operator()(double value) {
sum += value;
count++;
}
double getAverage() const {
return count > 0 ? sum / count : 0;
}
};
// 比较函数对象
class GreaterThan {
private:
int threshold;
public:
GreaterThan(int t) : threshold(t) {}
bool operator()(int value) const {
return value > threshold;
}
};
int main() {
// 使用函数对象
Multiplier times3(3);
cout << "5 * 3 = " << times3(5) << endl; // 15
cout << "7 * 3 = " << times3(7) << endl; // 21
// 在算法中使用
vector numbers = {1, 2, 3, 4, 5};
transform(numbers.begin(), numbers.end(), numbers.begin(), Multiplier(10));
cout << "After transform: ";
for (int n : numbers) cout << n << " ";
cout << endl;
// 带状态的函数对象
Average avg;
avg(10.0);
avg(20.0);
avg(30.0);
cout << "Average: " << avg.getAverage() << endl;
// 查找大于5的元素
auto it = find_if(numbers.begin(), numbers.end(), GreaterThan(25));
if (it != numbers.end()) {
cout << "First > 25: " << *it << endl;
}
return 0;
}
===== 7.5 类型转换运算符 =====
=== 7.5.1 转换构造函数 ===
#include
using namespace std;
class Rational {
private:
int numerator;
int denominator;
public:
Rational(int n = 0, int d = 1) : numerator(n), denominator(d) {
if (denominator == 0) denominator = 1;
}
// 类型转换运算符:Rational -> double
operator double() const {
return static_cast(numerator) / denominator;
}
// 类型转换运算符:Rational -> bool
explicit operator bool() const { // explicit防止隐式转换
return numerator != 0;
}
// 友元输出
friend ostream& operator<<(ostream& os, const Rational& r) {
os << r.numerator << "/" << r.denominator;
return os;
}
};
int main() {
Rational r(3, 4);
// 隐式转换为double
double d = r; // 调用 operator double()
cout << r << " = " << d << endl; // 0.75
// 在算术运算中隐式转换
double result = r + 0.5; // r隐式转换为double
cout << "r + 0.5 = " << result << endl;
// explicit bool需要显式转换
// bool flag = r; // 错误!explicit
bool flag = static_cast(r); // 正确
if (r) { // 条件上下文可以隐式转换
cout << "r is non-zero" << endl;
}
return 0;
}
=== 7.5.2 explicit关键字 ===
#include
using namespace std;
class String {
private:
char* data;
size_t length;
public:
// explicit禁止隐式转换
explicit String(size_t n) {
length = n;
data = new char[n + 1]();
cout << "Created string of length " << n << endl;
}
String(const char* str) {
length = strlen(str);
data = new char[length + 1];
strcpy(data, str);
}
~String() { delete[] data; }
};
void printString(const String& s) {
cout << "String printed" << endl;
}
int main() {
String s1(100); // 正确,显式构造
String s2 = String(100); // 正确,显式构造
// String s3 = 100; // 错误!构造函数是explicit
printString(String(50)); // 正确,显式构造
// printString(50); // 错误!不能隐式转换
String s4 = "Hello"; // 正确,String(const char*)不是explicit
printString("World"); // 正确,隐式转换
return 0;
}
===== 7.6 智能指针运算符 =====
=== 7.6.1 自定义智能指针 ===
#include
using namespace std;
template
class SmartPtr {
private:
T* ptr;
size_t* refCount;
void release() {
if (refCount) {
(*refCount)--;
if (*refCount == 0) {
delete ptr;
delete refCount;
cout << "Resource deleted" << endl;
}
}
}
public:
explicit SmartPtr(T* p = nullptr) : ptr(p) {
refCount = ptr ? new size_t(1) : nullptr;
}
// 拷贝构造函数
SmartPtr(const SmartPtr& other) : ptr(other.ptr), refCount(other.refCount) {
if (refCount) (*refCount)++;
}
// 拷贝赋值
SmartPtr& operator=(const SmartPtr& other) {
if (this != &other) {
release();
ptr = other.ptr;
refCount = other.refCount;
if (refCount) (*refCount)++;
}
return *this;
}
~SmartPtr() {
release();
}
// 解引用运算符
T& operator*() const {
return *ptr;
}
// 成员访问运算符
T* operator->() const {
return ptr;
}
// 转换为bool
explicit operator bool() const {
return ptr != nullptr;
}
// 获取原始指针
T* get() const { return ptr; }
// 获取引用计数
size_t use_count() const {
return refCount ? *refCount : 0;
}
};
class Test {
public:
void sayHello() { cout << "Hello!" << endl; }
};
int main() {
SmartPtr p1(new Test());
cout << "Ref count: " << p1.use_count() << endl; // 1
SmartPtr p2 = p1;
cout << "Ref count: " << p1.use_count() << endl; // 2
p1->sayHello();
(*p2).sayHello();
if (p1) {
cout << "p1 is valid" << endl;
}
return 0;
}
===== 7.7 其他运算符 =====
=== 7.7.1 指针访问运算符 ===
#include
using namespace std;
class Proxy {
private:
int data;
public:
Proxy(int d) : data(d) {}
void proxyMethod() { cout << "Proxy method: " << data << endl; }
};
class Wrapper {
private:
Proxy* proxy;
public:
Wrapper(int d) : proxy(new Proxy(d)) {}
~Wrapper() { delete proxy; }
// 重载 -> 运算符
Proxy* operator->() {
return proxy;
}
// const版本
const Proxy* operator->() const {
return proxy;
}
};
int main() {
Wrapper w(42);
w->proxyMethod(); // 等价于 (w.operator->())->proxyMethod()
return 0;
}
=== 7.7.2 new和delete运算符重载 ===
#include
#include
using namespace std;
class MemoryTracked {
private:
static size_t totalAllocated;
static size_t totalFreed;
public:
// 重载new
void* operator new(size_t size) {
totalAllocated += size;
cout << "Allocating " << size << " bytes" << endl;
return malloc(size);
}
// 重载new[]
void* operator new[](size_t size) {
totalAllocated += size;
cout << "Allocating array of " << size << " bytes" << endl;
return malloc(size);
}
// 重载delete
void operator delete(void* ptr, size_t size) {
totalFreed += size;
cout << "Deallocating " << size << " bytes" << endl;
free(ptr);
}
// 重载delete[]
void operator delete[](void* ptr, size_t size) {
totalFreed += size;
cout << "Deallocating array of " << size << " bytes" << endl;
free(ptr);
}
static void printStats() {
cout << "Total allocated: " << totalAllocated << endl;
cout << "Total freed: " << totalFreed << endl;
}
};
size_t MemoryTracked::totalAllocated = 0;
size_t MemoryTracked::totalFreed = 0;
int main() {
MemoryTracked* obj = new MemoryTracked();
delete obj;
MemoryTracked* arr = new MemoryTracked[5];
delete[] arr;
MemoryTracked::printStats();
return 0;
}
===== 7.8 本章小结 =====
本章我们学习了:
* 运算符重载的基本规则和限制
* 成员函数方式重载运算符
* 友元函数方式重载运算符
* 赋值运算符和下标运算符的实现
* 函数调用运算符和函数对象
* 类型转换运算符和explicit关键字
* 智能指针运算符的重载
* 内存分配运算符的重载
===== 练习题 =====
**基础练习:**
1. 完善Complex类,实现/、+=、-=、*=、/=运算符
2. 实现一个BigInteger类,支持大整数的基本运算
3. 设计一个Matrix类,实现矩阵的+、-、*运算和[]访问
4. 实现一个安全的数组类,支持边界检查
**进阶练习:**
5. 实现一个字符串类MyString,支持所有必要的运算符
6. 设计一个二维向量类Vector2D,实现点积、叉积等运算
7. 实现一个日期类Date,支持日期加减和比较运算
**思考题:**
8. 为什么有些运算符只能作为成员函数重载(如=、[]、->)?
9. 前置++和后置++在效率上有什么区别?
10. 研究C++20的三路比较运算符<=>(太空船运算符)
===== 参考答案 =====
**练习3参考:**
class Matrix {
private:
vector> data;
size_t rows, cols;
public:
Matrix(size_t r, size_t c) : rows(r), cols(c), data(r, vector(c)) {}
double& operator()(size_t i, size_t j) { return data[i][j]; }
const double& operator()(size_t i, size_t j) const { return data[i][j]; }
Matrix operator+(const Matrix& other) const {
Matrix result(rows, cols);
for (size_t i = 0; i < rows; i++)
for (size_t j = 0; j < cols; j++)
result(i, j) = (*this)(i, j) + other(i, j);
return result;
}
Matrix operator*(const Matrix& other) const {
Matrix result(rows, other.cols);
for (size_t i = 0; i < rows; i++)
for (size_t j = 0; j < other.cols; j++)
for (size_t k = 0; k < cols; k++)
result(i, j) += (*this)(i, k) * other(k, j);
return result;
}
};
===== 下一章 =====
继续学习:[[第八章_模板|第八章 模板]]