day33-c++运算符重载

day33-c++运算符重载

一、什么是运算符重载

运算符重载是一种特殊的函数重载,它允许我们为自定义的类或结构定义新的运算符含义,从而实现不同类型数据之间的操作。例如,我们可以重载加号运算符(+)来实现两个复数或者两个矩阵的相加。

运算符重载的本质是定义一个函数,并告诉c++编译器,当遇到该运算符时就调用此函数来执行相应的操作。这个函数叫做运算符重载函数,它可以是类的成员函数,也可以是类的友元函数。

C++编译器会根据操作数的类型来判断是否要调用操作符重载函数。如果操作数是用户自定义的类型,且存在一个匹配的操作符重载函数,那么就会调用这个函数。如果操作数是内置的类型,或者不存在一个匹配的操作符重载函数,那么就会使用操作符的原始含义。

二、为什么要运算符重载

运算符重载的目的是为了提高代码的可读性和简洁性,让我们可以用自然的方式表达自定义类型之间的操作。例如,如果我们定义了一个分数类Fraction,我们可以通过重载加号运算符来实现两个分数对象的相加,而不需要调用一个特定的函数。

三、运算符重载形式

运算符重载函数的一般形式如下:

1
2
3
返回值类型 operator 运算符 (参数列表) {
// 函数体
}

其中,operator是关键字,它与要重载的运算符一起构成函数名。返回值类型和参数列表根据不同的运算符和需求而定。

根据参数个数的不同,我们可以将运算符分为一元运算符和二元运算符。一元运算符只有一个参数,二元运算符有两个参数。例如:

1
2
3
4
5
6
7
8
9
// 一元运算符 - 的重载
Complex operator- () {
return Complex(-real, -imag);
}

// 二元运算符 + 的重载
Complex operator+ (const Complex& c) {
return Complex(real + c.real, imag + c.imag);
}

根据定义位置的不同,我们可以将运算符分为类内重载和类外重载。

  • 类内重载:将运算符重载函数作为类的成员函数,这样可以直接访问类的私有成员。类内重载的函数通常只有一个参数,表示运算符的右操作数,左操作数默认为调用该函数的对象。
  • 类外重载:将运算符重载函数作为类的友元函数或普通函数,这样需要显式地传递运算符的左右操作数。类外重载的函数通常有两个参数,分别表示运算符的左右操作数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Point {
public:
Point(int x, int y) : x(x), y(y) {}
// 类内重载 + 运算符
Point operator+ (const Point& p) {
return Point(x + p.x, y + p.y);
}
friend Point operator- (const Point& p1, const Point& p2);
private:
int x, y;
};

// 类外重载 - 运算符
Point operator- (const Point& p1, const Point& p2) {
return Point(p1.x - p2.x, p1.y - p2.y);
}

一般来说,当要操作类中私有成员时就用类内重载或者友员函数重载。当操作公用的成员时就能用类外普通函数重载。

四、运算符重载的分类

根据运算符操作数的个数,可以将运算符分为一元运算符和二元运算符。

  • 一元运算符:只有一个操作数,例如 +、-、*、&、!、++、– 等。一元运算符可以作为前置或后置形式使用,例如 ++a 或 a++。一元运算符重载时,如果是类内重载,则不需要参数;如果是类外重载,则需要一个参数。
  • 二元运算符:有两个操作数,例如 +、-、*、/、%、==、!=、<、> 等。二元运算符重载时,如果是类内重载,则需要一个参数;如果是类外重载,则需要两个参数。

另外,还有一些特殊的运算符,例如 ()、[]、-> 等,它们也可以进行重载,但必须作为类的成员函数进行类内重载。

自增分为前自增和后自增,这两个在语法上有一定的区别(后置++的参数要多个占位符int),输入和输出重载返回值和参数有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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
using namespace std;

class Point {
public:
Point(int x, int y) : x(x), y(y) {}
Point& operator+ (const Point& p) { //类内实现操作符重载
Point* temp = new Point(x + p.x, y + p.y);
return *temp;
}

//上面这种返回引用有个问题,这样返回对象会造成一定的空间浪费,因为你需要在堆上分配一个临时对象,然后在栈上分配一个临时对象的拷贝。而且,临时对象的生命周期是由它所绑定的引用决定的,因为你返回了一个临时对象的引用,所以它的生命周期会延长到引用的生命周期结束为止,你还需要手动释放堆上的临时对象。


friend Point operator+(const Point &p1, const Point &p2) {//类外友联实现操作符重载
return Point(p1.x + p2.x, p1.y + p2.y);
}
//这样返回不会造成空间浪费,当函数结束后临时对象会自动销毁

friend Point operator++ (Point& p1, int){ //后置++
return Point(p1.x++,p1.y++);
}
friend Point operator++ (Point& p1){ //前置++
return Point(++p1.x,++p1.y);
}

friend ostream &operator<<(ostream &os, const Point &p) { //输入重载
os << "x=" << p.x << ",y=" << p.y << endl;
return os;
}
friend istream &operator>>(istream &is, Point &p) { //输出重载
is >> p.x >> p.y;
return is;
}
int operator()( int a, int b) { //括号重载,不能用友员函数写
this->x +=a;
this->y +=b;
}


private:
int x, y;
};


int main(void){
Point a(12,13);
cin >> a ;
Point b(14,15);
Point c=b+(a++);
cout<<"a:"<<a;
a(1,2);
cout<<"c:"<<c;
cout<<"a:"<<a;

return 0;
}

//14 15
//a:x=15,y=16
//c:x=28,y=30
//a:x=16,y=18

//14 15
//a:x=15,y=16
//c:x=28,y=30
//a:x=16,y=18
Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2020-2024 nakano-mahiro
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信