跳至内容
张叶安的小站
用户工具
登录
站点工具
搜索
工具
显示页面
过去修订
反向链接
最近更改
媒体管理器
网站地图
登录
>
最近更改
媒体管理器
网站地图
您的足迹:
cplus:第七章运算符重载
本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。
====== 第七章 运算符重载 ====== 本章将详细介绍C++的运算符重载机制,包括成员函数重载、友元函数重载、类型转换运算符等。 ===== 7.1 运算符重载基础 ===== === 7.1.1 基本概念 === 运算符重载允许为自定义类型定义运算符的行为,使代码更直观、更自然。 <code cpp> #include <iostream> 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; } </code> === 7.1.2 可重载的运算符 === | 运算符类别 | 可重载运算符 | |-----------|-------------| | 算术 | +, -, *, /, % | | 关系 | ==, !=, <, >, <=, >= | | 逻辑 | !, &&, || | | 位运算 | ~, &, |, ^, <<, >> | | 赋值 | =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= | | 自增/自减 | ++, -- | | 内存 | new, delete, new[], delete[] | | 访问 | [], (), ->, ->*, .* | | 其他 | , (逗号), & (取地址), * (解引用) | 不可重载的运算符: * ::(作用域解析) * .(成员访问) * .*(成员指针访问) * ?:(三元条件) * sizeof * typeid ===== 7.2 成员函数重载 ===== === 7.2.1 单目运算符重载 === <code cpp> #include <iostream> 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; } </code> === 7.2.2 赋值运算符重载 === <code cpp> #include <iostream> #include <cstring> 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; } </code> === 7.2.3 下标运算符重载 === <code cpp> #include <iostream> #include <stdexcept> 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<int>(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; } </code> ===== 7.3 友元函数重载 ===== === 7.3.1 二元运算符的友元重载 === <code cpp> #include <iostream> 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; } </code> === 7.3.2 输入输出运算符重载 === <code cpp> #include <iostream> #include <string> 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; } </code> ===== 7.4 函数调用运算符重载 ===== === 7.4.1 函数对象(Functor) === <code cpp> #include <iostream> #include <vector> #include <algorithm> 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<int> 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; } </code> ===== 7.5 类型转换运算符 ===== === 7.5.1 转换构造函数 === <code cpp> #include <iostream> 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<double>(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<bool>(r); // 正确 if (r) { // 条件上下文可以隐式转换 cout << "r is non-zero" << endl; } return 0; } </code> === 7.5.2 explicit关键字 === <code cpp> #include <iostream> 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; } </code> ===== 7.6 智能指针运算符 ===== === 7.6.1 自定义智能指针 === <code cpp> #include <iostream> using namespace std; template<typename T> 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<Test> p1(new Test()); cout << "Ref count: " << p1.use_count() << endl; // 1 SmartPtr<Test> p2 = p1; cout << "Ref count: " << p1.use_count() << endl; // 2 p1->sayHello(); (*p2).sayHello(); if (p1) { cout << "p1 is valid" << endl; } return 0; } </code> ===== 7.7 其他运算符 ===== === 7.7.1 指针访问运算符 === <code cpp> #include <iostream> 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; } </code> === 7.7.2 new和delete运算符重载 === <code cpp> #include <iostream> #include <cstdlib> 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; } </code> ===== 7.8 本章小结 ===== 本章我们学习了: * 运算符重载的基本规则和限制 * 成员函数方式重载运算符 * 友元函数方式重载运算符 * 赋值运算符和下标运算符的实现 * 函数调用运算符和函数对象 * 类型转换运算符和explicit关键字 * 智能指针运算符的重载 * 内存分配运算符的重载 ===== 练习题 ===== **基础练习:** 1. 完善Complex类,实现/、+=、-=、*=、/=运算符 2. 实现一个BigInteger类,支持大整数的基本运算 3. 设计一个Matrix类,实现矩阵的+、-、*运算和[]访问 4. 实现一个安全的数组类,支持边界检查 **进阶练习:** 5. 实现一个字符串类MyString,支持所有必要的运算符 6. 设计一个二维向量类Vector2D,实现点积、叉积等运算 7. 实现一个日期类Date,支持日期加减和比较运算 **思考题:** 8. 为什么有些运算符只能作为成员函数重载(如=、[]、->)? 9. 前置++和后置++在效率上有什么区别? 10. 研究C++20的三路比较运算符<=>(太空船运算符) ===== 参考答案 ===== **练习3参考:** <code cpp> class Matrix { private: vector<vector<double>> data; size_t rows, cols; public: Matrix(size_t r, size_t c) : rows(r), cols(c), data(r, vector<double>(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; } }; </code> ===== 下一章 ===== 继续学习:[[第八章_模板|第八章 模板]]
cplus/第七章运算符重载.txt
· 最后更改:
2026/02/03 19:45
由
127.0.0.1
页面工具
显示页面
过去修订
反向链接
回到顶部