C++中运算符的重载

概念

C++中运算符可以通过下面的方式重载,从而为自定义类型定义运算。

1
返回类型 operator运算符(参数列表);

可以重载的运算符包括

  • 算术运算符(+-*/
  • 关系运算符(==!=<>
  • 赋值运算符(=
  • 插入流和提取流运算符(<<>>

等。

运算符重载实例

1. 算术运算符(+-*/

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
#include <iostream>
using namespace std;

class Complex {
private:
double real;
double imag;

public:
// 这里仅是为了举例,实际项目中不建议使用默认参数
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}

// 成员函数形式重载+
Complex operator+(const Complex& other) {
return Complex(real + other.real, imag + other.imag);
}

// 成员函数形式重载-
Complex operator-(const Complex& other) {
return Complex(real - other.real, imag - other.imag);
}

void display() {
cout << real << " + " << imag << "i" << endl;
}
};

int main() {
Complex c1(3.0, 4.0);
Complex c2(1.0, 2.0);

Complex c3 = c1 + c2; // 使用重载的+运算符
c3.display(); // 输出:4 + 6i

Complex c4 = c1 - c2; // 使用重载的-运算符
c4.display(); // 输出:2 + 2i

return 0;
}

算符运算符重载的返回值是同类型的对象

  • 因为算术运算符本身就不修改操作符,返回同类型的对象符合语义
  • 算术运算符本身就要在操作符函数内产生新的对象,这个对象的作用域局限在函数内部,如果返回引用的话,这个引用所绑定的对象在函数结束后会被释放,返回引用会出现段错误
    1
    2
    3
    Complex& operator+(const Complex& other) const {
    return Complex(real + other.real, imag + other.imag);//error,cannot bind non-const lvalue reference of type ‘Complex&’ to an rvalue of type ‘Complex’
    }
    如果返回引用,就不能向上面这样写了,因为这样写的返回值是一个不具名的右值,不能绑定到左值引用。
    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
    #include <iostream>

    class Complex {
    private:
    double real;
    double imag;
    public:
    Complex(int r, int i):real(r),imag(i) {
    std::cout << "Complex(int, int) constructor called" << std::endl;
    }
    Complex& operator+(const Complex& other) const {
    Complex result(real + other.real, imag + other.imag);
    return result;
    }
    void print() const {
    std::cout << real << " + " << imag << "i" << std::endl;
    }
    ~Complex() {
    std::cout << "Complex destructor called" << std::endl;
    }
    };

    int main() {
    Complex num1(3, 4);
    Complex num2(1, 2);
    Complex result = num1 + num2;
    std::cout << "num1 = :";
    num1.print();
    std::cout << "num2 = :";
    num2.print();
    std::cout << "num1 + num2 = :";
    result.print();
    return 0;
    }
    上代码的输出是
    1
    2
    3
    4
    Complex(int, int) constructor called
    Complex(int, int) constructor called
    Complex(int, int) constructor called
    Complex destructor called
    并且在运行到Complex result = num1 + num2;出现了段错误Segmentation fault,说明result在函数结束时就已经析构,因此Complex&找不到要绑定的对象。

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
using namespace std;

class Complex {
private:
double real;
double imag;

public:
// 同上,这里仅是为了举例,实际项目中不建议使用默认参数
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}

// 成员函数形式重载==
bool operator==(const Complex& other) {
return (real == other.real) && (imag == other.imag);
}

// 成员函数形式重载!=
bool operator!=(const Complex& other) {
return !(*this == other);
}

void display() {
cout << real << " + " << imag << "i" << endl;
}
};

int main() {
Complex c1(3.0, 4.0);
Complex c2(3.0, 4.0);
Complex c3(1.0, 2.0);

if (c1 == c2) {
cout << "c1 and c2 are equal." << endl;
} else {
cout << "c1 and c2 are not equal." << endl;
}

if (c1 != c3) {
cout << "c1 and c3 are not equal." << endl;
} else {
cout << "c1 and c3 are equal." << endl;
}

return 0;
}

3. 赋值运算符(=

需要注意的是

  • 返回值应该是对象的引用
    • 允许进行连续赋值 obj3 = obj2 = obj1
    • 防止返回对象时调用拷贝构造函数和析构函数,造成不必要的开销
  • 需要注意自赋值问题
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
43
44
45
46
47
48

#include <iostream>
#include <cstring>
using namespace std;

class MyString {
private:
char* str;

public:
MyString(const char* s = "") {
str = new char[strlen(s) + 1];
strcpy(str, s);
}

// 析构函数
~MyString() {
delete[] str;
}

// 赋值运算符重载
MyString& operator=(const MyString& other) {
if (this == &other) {
return *this; // 处理自我赋值
}
delete[] str; // 释放原有内存
str = new char[strlen(other.str) + 1];
strcpy(str, other.str);
return *this;
}

void display() {
cout << str << endl;
}
};

int main() {
MyString s1("Hello");
MyString s2("World");

s1.display(); // 输出:Hello
s2.display(); // 输出:World

s2 = s1; // 使用重载的=运算符
s2.display(); // 输出:Hello

return 0;
}

4. 插入流和提取流运算符(<<>>

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
#include <iostream>
using namespace std;

class Complex {
private:
double real;
double imag;

public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}

// 友元函数形式重载<<
friend ostream& operator<<(ostream& os, const Complex& c);
};

ostream& operator<<(ostream& os, const Complex& c) {
os << c.real << " + " << c.imag << "i";
return os;
}

int main() {
Complex c;
cout << c << endl; // 使用重载的<<运算符
return 0;
}

注意事项

  • 以下的运算符不能重载
    • 成员访问运算符 .
    • 成员指针访问 .*
    • 作用域解析运算符 ::
    • 条件运算符 ?:
    • sizeof运算符
  • 运算符重载不能改变运算符的优先级和结合性
  • 基本数据类型的运算符不能重载,如果运算符有2个及以上操作数,则至少一个操作数是自定义类型

C++中运算符的重载
https://guts.homes/2025/06/13/cpp-operator-overload/
作者
guts
发布于
2025年6月13日
许可协议