在 C++ 中,自定义数据类型(如类、结构体)可以通过对运算符重载,实现像内置数据类型一样使用运算符(如 +、-、*、<< 等),从而增强代码的可读性和易用性。运算符重载本质上是函数重载,因此需遵循特定的语法和规则。
一、基本语法
运算符重载有两种形式:成员函数和非成员函数(全局函数)。
1.1 成员函数形式
1 2 3
| 返回类型 operator 运算符(参数列表) { }
|
该形式适用于大部分二元运算符(如 +、-、*、/)、一元运算符(如 ++、–、!)等。
1.2 全局函数形式(通常为友元函数)
1 2 3
| 返回类型 operator 运算符(参数列表) { }
|
通常作为全局(友元)函数的运算符:
- 流 I/O 运算符
<< 和 >>(因为左操作数是 std::ostream 或 std::istream,我们无法修改标准库类)。
- 对称的双目运算符(如
+, -, ==),以便支持左侧操作数的隐式类型转换。例如 double + Complex。
二、运算符重载的基本规则
2.1 可被重载的运算符
2.1.1 算术运算符
a. 双目:+(加)、-(减)、(乘)、/(除)、%(取余)
b. 单目:+(正号)、-(负号)、++(自增)、–(自减)
2.1.2 赋值运算符
a. 基础赋值:=(注意:默认会生成,但若自定义需手动重载)
b. 复合赋值:+=、-=、=、/=、%=、&=、|=、^=、<<=、>>=
2.1.3 比较运算符
a. ==(等于)
b. !=(不等于)
c. <(小于)
d. >(大于)
e. <=(小于等于)
f. >=(大于等于)
2.1.4 逻辑运算符
a. !(逻辑非)
b. &&(逻辑与)
c. ||(逻辑或)
⚠️ 注意:重载后不支持短路求值(与内置逻辑运算符不同)。
2.1.5 位运算符
a. 位逻辑:&(位与)、|(位或)、^(位异或)、~(位非)
b. 移位:<<(左移)、>>(右移)
2.1.6 成员访问运算符
a. ->(成员指针访问)
b. ->*(指向成员的指针访问)
c. [](下标访问,仅能重载为成员函数)
2.1.7 函数调用运算
a. ()函数调用,可重载为成员函数,使对象像函数一样被调用,即 “仿函数”。
2.1.8 内存管理运算符
a. new(动态内存分配)、delete(动态内存释放);
b. new[](数组动态分配)、delete[](数组动态释放)。
2.1.9 其他运算符
a. , 逗号运算符,重载后改变其 “顺序求值并返回最后一个值” 的语义;
b. & 取地址符,可重载为成员函数,返回自定义指针;
c. * 解引用运算符,常与 -> 配合用于智能指针。
可重载的运算符覆盖了大多数常用操作,通过重载可使自定义类型的使用更接近内置类型(如 a + b、obj[i] 等)。
2.2 不可被重载的运算符
1、 .(成员访问运算符,如 obj.member)
2、 .*(成员指针访问运算符,如 obj.*ptr)
3、 ::(作用域解析运算符,如 std::cout)
4、 ?:(三目条件运算符,如 a ? b : c)
5、 sizeof(求大小运算符,如 sizeof(int))
6、 typeid(类型信息运算符,用于获取类型信息)
7、 const_cast、static_cast、dynamic_cast、reinterpret_cast(类型转换运算符)
2.3 使用限制
- 不能创建新的运算符:只能重载 C++ 中已有的运算符(例如不能创建
** 运算符表示幂运算)。
- 不能改变运算符的优先级和结合性:例如,
* 的优先级永远高于 +。
- 不能改变操作数的个数:单目运算符依然是单目,双目依然是双目。
- 不能重载内置类型的运算符:至少有一个操作数必须是用户自定义类型(类/结构体/枚举)。
- 重载运算符时应遵循原运算符的语义:如
+ 应表示 “相加”
- 以下运算符与当前对象强绑定,因此必须为成员函数:
- 赋值运算符
=
- 下标运算符
[]
- 函数调用运算符
()
- 成员访问运算符
->
三、常用运算符重载示例
3.1 算术运算符
成员函数形式(左操作数为当前对象):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Point { public: Point(int x = 0, int y = 0) : _x(x), _y(y) {} Point operator+(const Point& other) const { return Point(_x + other._x, _y + other._y); } public: int _x; int _y; };
|
非成员函数形式(支持混合类型,如 Point + int):
1 2 3 4 5 6 7 8 9 10 11 12
| Point operator+(const Point& p, int val) { return Point(p._x + val, p._y); }
Point operator+(int val, const Point& p) { return Point(p._x + val, p._y); }
|
3.2 自增/自减运算符
需区分前置(++a)和后置(a++),语法上通过参数区分(后置版本多一个 int 占位参数)。
前置 ++(成员函数):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Counter { public: Counter(int c = 0) : _count(c) {} Counter& operator++() { _count++; return *this; } private: int _count; };
|
后置 ++(成员函数):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Counter { public: Counter(int c = 0) : _count(c) {} Counter operator++(int) { Counter temp = *this; _count++; return temp; } private: int _count; };
|
3.2 赋值运算符(=、+= 等)
默认情况下,编译器会生成默认赋值运算符(浅拷贝),但涉及指针时需手动重载(实现深拷贝)。
赋值运算符 =(成员函数,必须为成员函数):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class String { public: String(const char* s = "") { _data = new char[strlen(s) + 1]; strcpy(_data, s); } ~String() { delete[] _data; } public: String& operator=(const String& other) { if (this != &other) { delete[] _data; _data = new char[strlen(other._data) + 1]; strcpy(_data, other._data); } return *this; } private: char* _data; };
|
复合赋值运算符 +=(成员函数):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class String { public: String(const char* s = "") { _data = new char[strlen(s) + 1]; strcpy(_data, s); } ~String() { delete[] _data; } public: String& operator+=(const String& other) { char* newData = new char[strlen(_data) + strlen(other._data) + 1]; strcpy(newData, _data); strcat(newData, other._data); delete[] _data; _data = newData; return *this; } private: char* _data; };
|
3.4 比较运算符(==、!= 等)
通常重载为非成员函数,保证对称性(如 a == 5 和 5 == a 均可)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Point { public: Point(int x = 0, int y = 0) : _x(x), _y(y) {} Point operator+(const Point& other) const { return Point(_x + other._x, _y + other._y); } public: int _x; int _y; };
bool operator==(const Point& a, const Point& b) { return a._x == b._x && a._y == b._y; }
bool operator!=(const Point& a, const Point& b) { return !(a == b); }
|
3.5 逻辑运算符(&&、||、!)
运算符&&、|| 重载后短路求值特性会失效,因为运算符重载本质上是通过函数调用实现的(编译器会将 a && b 转换为 operator&&(a, b) 或 a.operator&&(b))。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class BitVector { public: BitVector(uint32_t bits = 0) : _bits(bits) {} public: uint32_t GetBits() const { return _bits; } bool operator!() const { return _bits == 0; } friend bool operator&&(const BitVector& a, const BitVector& b);
friend bool operator||(const BitVector& a, const BitVector& b);
private: uint32_t _bits; };
bool operator&&(const BitVector& a, const BitVector& b) { return (a._bits != 0) && (b._bits != 0); }
bool operator||(const BitVector& a, const BitVector& b) { return (a._bits != 0) || (b._bits != 0); }
|
3.6 位运算符(&、|、^、~、<<、>>)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| class BitVector { public: BitVector(uint32_t bits = 0) : _bits(bits) {} public: BitVector operator~() const { return BitVector(~_bits); } BitVector operator&(const BitVector& other) const { return BitVector(_bits & other._bits); } BitVector operator|(const BitVector& other) const { return BitVector(_bits | other._bits); } BitVector operator^(const BitVector& other) const { return BitVector(_bits ^ other._bits); } BitVector operator<<(int n) const { return BitVector(_bits << n); } BitVector operator>>(int n) const { return BitVector(_bits >> n); } private: uint32_t _bits; };
|
3.7 输入、输出运算符(<<、>>)
必须重载为非成员函数(因为左操作数是 ostream 或 istream,无法作为自定义类的成员),通常声明为友元以访问私有成员。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <iostream> using namespace std; class Point { public: Point(int x = 0, int y = 0) : _x(x), _y(y) {} Point operator+(const Point& other) const { return Point(_x + other._x, _y + other._y); } public: friend ostream& operator<<(ostream& os, const Point& p); friend istream& operator>>(istream& is, Point& p); public: int _x; int _y; };
ostream& operator<<(ostream& os, const Point& p) { os << "(" << p._x << ", " << p._y << ")"; return os; }
istream& operator>>(istream& is, Point& p) { is >> p._x >> p._y; return is; }
|
3.8 下标运算符 []
通常重载为成员函数,用于自定义容器类(如数组封装)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class Array { public: Array(int s = 0) : _size(s) { _data = new int[_size]; } int& operator[](int index) { if (index < 0 || index >= _size) { throw out_of_range("下标越界"); } return _data[index]; } const int& operator[](int index) const { if (index < 0 || index >= _size) { throw out_of_range("下标越界"); } return _data[index]; } private: int* _data; int _size; };
|
3.9 函数调用运算符 ()
重载后,对象可像函数一样被调用(“函数对象”或“仿函数”)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Add { public: Add(int b) : _base(b) {} int operator()(int x) const { return _base + x; } private: int _base; };
|