c++运算符重载
·
1、原理
在c++中,运算符其实就是特殊名字的函数。
普通函数:
int add(int a,int b) {return a + b;}
运算符重载:
int operator+(int a, int b) { return a + b; }
编译器看到a+b,如果a或b是类对象,就会查找是否定义了operator+来处理。
注意:运算符重载 不会改变运算符的优先级和结合性,只改变“运算时的含义”。
2、运算重载符的使用
2.1 成员函数方式
class Number {
public:
int value;
Number(int v) : value(v) {}
// 成员函数重载 + (左边必须是本类对象)
Number operator+(const Number& other) const {
return Number(value + other.value);
}
};
int main() {
Number num1(10);
Number num2(20);
Number num3 = num1 + num2; //与num1.operator+(b)等价
cout << num3.value << endl;
return 0;
}
2.2 全局函数(友元)方式
class Number {
public:
int value;
Number(int v) : value(v) {}
// 让友元函数能访问私有成员
friend Number operator+(const Number& lhs, const Number& rhs);
};
// 定义全局函数
Number operator+(const Number& lhs, const Number& rhs) {
return Number(lhs.value + rhs.value);
}
int main() {
Number num1(10);
Number num2(20);
Number num3 = num1 + num2;//与num1.operator+(b)等价
cout << num3.value << endl;
return 0;
}
两种方式的区别:
成员函数:左操作数必须是本类对象
全局函数:更加灵活,比如int+Number也可以支持
3、常见可重载运算符
|
算术运算符:+ - * / % |
关系运算符:== != < > <= >= |
逻辑运算符:&& || ! |
|
输入输出:<< >> |
下标运算符:[] |
函数调用:() |
|
自增自减:++ -- |
赋值运算符:=(建议总是重载) |
其他:-> ->* , new delete |
4、常用模板
算术运算符
class Number {
int value;
public:
Number(int v = 0) : value(v) {}
// 加法
Number operator+(const Number& other) const {
return Number(value + other.value);
}
// 减法
Number operator-(const Number& other) const {
return Number(value - other.value);
}
// 乘法
Number operator*(const Number& other) const {
return Number(value * other.value);
}
// 除法(带异常处理)
Number operator/(const Number& other) const {
if (other.value == 0) throw runtime_error("除数不能为 0");
return Number(value / other.value);
}
int get() const { return value; }
};
赋值运算符
class MyClass {
int* data;
public:
MyClass(int v = 0) { data = new int(v); }
~MyClass() { delete data; }
// 赋值运算符重载
MyClass& operator=(const MyClass& other) {
if (this == &other) return *this; // 防止自赋值
*data = *(other.data); // 深拷贝
return *this;
}
};
比较运算符
class Person {
int age;
public:
Person(int a) : age(a) {}
bool operator==(const Person& other) const {
return age == other.age;
}
bool operator!=(const Person& other) const {
return age != other.age;
}
bool operator<(const Person& other) const {
return age < other.age;
}
bool operator>(const Person& other) const {
return age > other.age;
}
};
输出/输入运算符
class Point {
int x, y;
public:
Point(int x=0, int y=0): x(x), y(y) {}
// 输出
friend ostream& operator<<(ostream& os, const Point& p) {
os << "(" << p.x << "," << p.y << ")";
return os;
}
// 输入
friend istream& operator>>(istream& is, Point& p) {
is >> p.x >> p.y;
return is;
}
};
下标运算符
class Array {
int data[10];
public:
int& operator[](int index) { // 可修改
return data[index];
}
const int& operator[](int index) const { // 只读
return data[index];
}
};
自增自减
class Counter {
int value;
public:
Counter(int v=0): value(v) {}
// 前置 ++
Counter& operator++() {
++value;
return *this;
}
// 后置 ++
Counter operator++(int) {
Counter temp = *this;
value++;
return temp;
}
int get() const { return value; }
};
函数调用运算符
class Adder {
int base;
public:
Adder(int b): base(b) {}
int operator()(int x) const { // 调用对象像函数
return base + x;
}
};
Adder add5(5);
cout << add5(10); // 输出 15
指针
class SmartPtr {
int* ptr;
public:
SmartPtr(int* p): ptr(p) {}
~SmartPtr() { delete ptr; }
int& operator*() { return *ptr; } // *p
int* operator->() { return ptr; } // p->成员
};
5、一个极简的 2D 向量,用来演示运算符重载
#pragma once
#include <iostream>
// 加/减是逐分量运算;标量乘对每个分量生效;== 比较两个分量相等;<< 友好打印
struct Vec2 {
double x{0}, y{0};
Vec2() = default;
Vec2(double x, double y) : x(x), y(y) {}
// 加法:逐分量相加
// v3 = v1 + v2 等价于:v3 = Vec2(v1.x + v2.x, v1.y + v2.y)
Vec2 operator+(const Vec2& rhs) const {
return Vec2{x + rhs.x, y + rhs.y};
}
// 减法:逐分量相减
// v3 = v1 - v2 等价于:v3 = Vec2(v1.x - v2.x, v1.y - v2.y)
Vec2 operator-(const Vec2& rhs) const {
return Vec2{x - rhs.x, y - rhs.y};
}
// 复合赋值:+=
// v1 += v2 等价于:v1 = v1 + v2
Vec2& operator+=(const Vec2& rhs) {
x += rhs.x; y += rhs.y;
return *this;
}
// 一元取反:-v (方向取反)
// v2 = -v1 等价于:Vec2(-v1.x, -v1.y)
Vec2 operator-() const {
return Vec2{-x, -y};
}
// 与标量的乘法(右乘)
// v2 = v1 * 2 等价于:Vec2(v1.x*2, v1.y*2)
Vec2 operator*(double k) const {
return Vec2{x * k, y * k};
}
// 比较:两个分量都相等才算相等
bool operator==(const Vec2& rhs) const {
return x == rhs.x && y == rhs.y;
}
bool operator!=(const Vec2& rhs) const { return !(*this == rhs); }
// 友元:输出(友好打印)
// std::cout << v 输出形如 (x,y)
friend std::ostream& operator<<(std::ostream& os, const Vec2& v) {
return os << "(" << v.x << "," << v.y << ")";
}
// —— 可选:下标访问(演示):v[0] 是 x,v[1] 是 y —— //
double& operator[](int i) {
return (i == 0) ? x : y; // 为简单起见不做越界检查
}
const double& operator[](int i) const {
return (i == 0) ? x : y;
}
};
// 标量在左、向量在右的乘法(左乘)
// v2 = 2 * v1 等价于:Vec2(v1.x*2, v1.y*2)
inline Vec2 operator*(double k, const Vec2& v) {
return Vec2{v.x * k, v.y * k};
}
int main() {
Vec2 a{3, 4};
Vec2 b{1, -2};
// 基本:+ - 一元-
Vec2 s1 = a + b; // 加:逐分量 (3+1, 4+(-2)) = (4,2)
Vec2 s2 = a - b; // 减:逐分量 (3-1, 4-(-2)) = (2,6)
Vec2 neg = -a; // 取反:(-3, -4)
// 复合赋值:+=
Vec2 c = a;
c += b; // 等价于:c = c + b
// 标量乘:向量*标量 与 标量*向量 都支持
Vec2 m1 = a * 2; // (6,8)
Vec2 m2 = 2 * a; // (6,8)
// 比较:== !=
bool eq1 = (a == Vec2{3,4}); // true
bool eq2 = (a != b); // true
// 下标访问:0->x 1->y
double ax = a[0]; // 3
double ay = a[1]; // 4
// 友好输出:<<
std::cout << "a=" << a << "\n";
std::cout << "b=" << b << "\n";
std::cout << "a+b=" << s1 << "\n";
std::cout << "a-b=" << s2 << "\n";
std::cout << "-a=" << neg << "\n";
std::cout << "c=a; c+=b -> c=" << c << "\n";
std::cout << "a*2=" << m1 << ", 2*a=" << m2 << "\n";
std::cout << "eq1=" << std::boolalpha << eq1
<< ", eq2=" << eq2 << "\n";
std::cout << "a[0]=" << ax << ", a[1]=" << ay << "\n";
// —— “语法糖背后的等价形式” —— //
// a + b 等价于 a.operator+(b)
Vec2 sugar1 = a + b;
Vec2 same1 = a.operator+(b);
// 2 * a 等价于 ::operator*(2, a) (因为左操作数不是 Vec2)
Vec2 sugar2 = 2 * a;
Vec2 same2 = operator*(2, a);
// 输出验证
std::cout << "[sugar1=" << sugar1 << ", same1=" << same1 << "]\n";
std::cout << "[sugar2=" << sugar2 << ", same2=" << same2 << "]\n";
return 0;
}
更多推荐


所有评论(0)