C++ 运算符重载

在 C++ 中,自定义数据类型(如类、结构体)可以通过对运算符重载,实现像内置数据类型一样使用运算符(如 +、-、*、<< 等),从而增强代码的可读性和易用性。运算符重载本质上是函数重载,因此需遵循特定的语法和规则。

一、基本语法

运算符重载有两种形式:成员函数和非成员函数(全局函数)。

1.1 成员函数形式

1
2
3
返回类型 operator 运算符(参数列表) {
// 实现逻辑
}

该形式适用于大部分二元运算符(如 +、-、*、/)、一元运算符(如 ++、–、!)等。

1.2 全局函数形式(通常为友元函数)

1
2
3
返回类型 operator 运算符(参数列表) {
// 实现逻辑
}

通常作为全局(友元)函数的运算符:

  • 流 I/O 运算符 <<>>(因为左操作数是 std::ostreamstd::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_caststatic_castdynamic_castreinterpret_cast(类型转换运算符)

2.3 使用限制

  1. 不能创建新的运算符:只能重载 C++ 中已有的运算符(例如不能创建 ** 运算符表示幂运算)。
  2. 不能改变运算符的优先级和结合性:例如,* 的优先级永远高于 +
  3. 不能改变操作数的个数:单目运算符依然是单目,双目依然是双目。
  4. 不能重载内置类型的运算符:至少有一个操作数必须是用户自定义类型(类/结构体/枚举)。
  5. 重载运算符时应遵循原运算符的语义:如 + 应表示 “相加”
  6. 以下运算符与当前对象强绑定,因此必须为成员函数:
    • 赋值运算符 =
    • 下标运算符 []
    • 函数调用运算符 ()
    • 成员访问运算符 ->

三、常用运算符重载示例

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 + Point
Point operator+(const Point& other) const
{
// 返回新对象,不修改原对象
return Point(_x + other._x, _y + other._y);
}
public:
int _x;
int _y;
};
// 调用:Point c = a + b;(等价于 a.operator+(b))

非成员函数形式(支持混合类型,如 Point + int):

1
2
3
4
5
6
7
8
9
10
11
12
// 全局函数:Point + int(x 坐标相加)
Point operator+(const Point& p, int val)
{
return Point(p._x + val, p._y);
}
// 全局函数:int + Point(对称重载)
Point operator+(int val, const Point& p)
{
// 与上一个逻辑相同,参数顺序相反
return Point(p._x + val, p._y);
}
// 调用:Point c = a + 5; 或 Point c = 5 + a;

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; // 支持链式操作,如 ++(++a)
}
private:
int _count;
};
// Counter c(1);
// ++c; 前置,调用 operator++()

后置 ++(成员函数):

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) {}
// 后置++:返回修改前的副本,参数 int 仅用于区分,无实际意义
Counter operator++(int)
{
Counter temp = *this; // 保存当前状态
_count++; // 修改自身
return temp; // 返回修改前的副本
}
private:
int _count;
};
// Counter c(1);
// c++; 调用 operator++(int)

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);
}
// 支持链式赋值,如 a = b = c
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 + Point
Point operator+(const Point& other) const
{
// 返回新对象,不修改原对象
return Point(_x + other._x, _y + other._y);
}
public:
int _x;
int _y;
};
// 非成员函数:判断两个 Point 是否相等
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);
}
// 调用:if (a == b) { ... }
// 调用:if (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)
{
// 逻辑与:两边都非0(逻辑真)则返回true
return (a._bits != 0) && (b._bits != 0);
}
// 逻辑或 || (非成员函数)
bool operator||(const BitVector& a, const BitVector& b)
{
// 逻辑或:至少一边非0(逻辑真)则返回true
return (a._bits != 0) || (b._bits != 0);
}

// 调用
// BitVector a(0b00001111);
// BitVector b(0b00110011);
// if(a && b) {...}
// if(a || b) {...}6. 位运算符(&、|、^、~、<<、>>)

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;
};
// 调用
// BitVector a(0b00001111);
// a << 2;

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 + Point
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;
};
// 输出运算符:cout << Point
ostream& operator<<(ostream& os, const Point& p)
{
os << "(" << p._x << ", " << p._y << ")";
// 支持链式输出,如 cout << a << b
return os;
}
// 输入运算符:cin >> Point
istream& operator>>(istream& is, Point& p)
{
// 假设输入格式为 "x y"
is >> p._x >> p._y;
// 支持链式输入,如 cin >> a >> b
return is;
}
// 调用:
// Point p;
// cin >> p; // 输入:3 4
// cout << p; // 输出:(3, 4)

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;
};

// 调用
// Array arr(3);
// 写操作,调用 int& operator[]
// arr[0] = 10;

// 读操作,调用 int& operator[]
// cout << arr[0] << endl;
// const Array cArr(3);
// 调用 const int& operator[](只读)
// cout << cArr[0] << endl;

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) {}
// 重载(),实现 base + x
int operator()(int x) const
{
return _base + x;
}
private:
int _base;
};

// 调用
// 创建函数对象
// Add add5(5);
// 等价于 add5.operator()(3),输出 8
// cout << add5(3);

C++ 运算符重载
http://example.com/2026/05/29/C++-运算符重载/
作者
Yu xin
发布于
2026年5月29日
许可协议