运算符重载


四则运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person {  
public:
Person() {};
Person(int a, int b)
{
this->m_A = a;
this->m_B = b;
}

// 成员函数实现 + 号运算符重载
Person operator+(const Person& p) {
Person temp;
temp.m_A = this->m_A + p.m_A;
temp.m_B = this->m_B + p.m_B;
return temp;
}
private:
int m_A;
int m_B;
};
1
2
3
4
5
6
7
8
9
// 全局函数实现 + 号运算符重载  
Person operator+(const Person& p1, const Person& p2) {
Person temp(0, 0);
temp.m_A = p1.m_A + p2.m_A;
temp.m_B = p1.m_B + p2.m_B;
return temp;
}
// 成员函数和全局函数实现后的调用
Person p = p1 + p2;
1
2
3
4
5
6
7
8
9
10
// 运算符重载版本
Person operator+(const Person& p2, int val)
{
Person temp;
temp.m_A = p2.m_A + val;
temp.m_B = p2.m_B + val;
return temp;
}
// 调用
Person p = p1 + 10;

本质调用

1
2
3
4
// 成员函数
Person p = p1.operator+(p2);
// 全局函数
Person p = operator+(p1, p2);

其他运算符和 + 类似,只是注意精度别爆 int 以及除法特判除数为 0 情况

左移运算符

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
class Person {
// 设置友元,因为全局函数要使用私有变量
friend ostream& operator<<(ostream& out, Person& p);
public:
Person(){}
Person(int a, int b)
{
this->m_A = a;
this->m_B = b;
}

// 成员函数 实现不了
// void operator<<(cout) {
// }
// 直接传 cout 肯定有问题,只是方便理解,传对应的数据类型,cout 是个 ostream 输出流对象,传 ostream
// 这样是 p << cout 不是我们想要的效果,虽然用成员函数这样写实现后,我们 p << cout 也能正确输出
// 因为成员函数里本质是用 p 去调用 << 运算符
private:
int m_A;
int m_B;
};

// 全局函数实现左移重载
// ostream对象只能有一个
// 本质是 operator<< (cout, p) ----> cout << p
ostream& operator<<(ostream& cout, Person& p) {
cout << "a:" << p.m_A << " b:" << p.m_B;
return out;
}
1
2
3
4
5
6
7
// 这里面引用缘故,还可使用 out 起别名
ostream& operator<<(ostream& out, Person& p) {
out << "a:" << p.m_A << " b:" << p.m_B;
return out;
}
// 外部输出还是 cout
cout << p;
  • 注意传参和返回值都需要引用的存在
  • 因为标准输出流对象只能有一个,所以不能创建副本,返回值自然也不能传值
  • 返回值传引用是因为
  • 调用过程是:执行 cout << p ,左移运算符做了重载,传入 coutp
  • 然后执行函数体,就实现了重载,这里相当于是 ostream& out = cout

为了实现链式编程,返回值为 ostream& ,这样之后就可以 cout << p << endl

递增运算符

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
class MyInteger {
friend ostream& operator<<(ostream& out, MyInteger myint);
public:
MyInteger() {
m_Num = 0;
}
// 前置++
MyInteger& operator++() {
//先++
m_Num++;
//再返回
return *this;
}

// 后置++
// int 是占位符,表示 a++
MyInteger operator++(int) {
// 先返回
// 记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++;
MyInteger temp = *this;
m_Num++;
return temp;
}

private:
int m_Num;
};

ostream& operator<<(ostream& out, MyInteger myint) {
out << myint.m_Num;
return out;
}

// 调用
MyInter a;
cout << ++(++a);
cout << a++;
// 不存在 cout << (a++)++;
  • 前置加加返回引用是因为存在 ++(++a) 这种情况,我们要实现这种,就需要返回引用
  • 因为不返回引用,第一次 ++a 后是创建的一个副本即新对象作为 ++a 的结果,那么此时再执行 ++a 虽然能够使 ++(++a) 得到正确的结果,但是 a 却不是,因为第二次的加加不是在 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
28
29
30
31
32
33
34
35
36
37
38
39
class Person {
public:
Person() : m_age(nullptr){}
Person(int age) {
m_Age = new int(age);
}

//重载赋值运算符
Person& operator=(const Person &p)
{
if (m_Age != NULL) {
delete m_Age;
m_Age = NULL;
}
//编译器提供的代码是浅拷贝
//m_Age = p.m_Age;

//提供深拷贝 解决浅拷贝的问题
m_Age = new int(*p.m_Age);

//返回自身
return *this;
}

~Person()
{
if (m_Age != NULL) {
delete m_Age;
m_Age = NULL;
}
}
private:
int *m_Age;
};

// 调用
Person p1(10);
Person p2, p3;
p3 = p2 = p1;
  • 注意实例化对象不初始化,需要在默认构造函数里指针指向空,不然是野指针,随意指向一块空间,此时进入拷贝构造函数,就会释放非法内存,导致崩溃
  • 这是应对指针的拷贝构造函数,默认拷贝构造会造成释放同一块内存区域的问题,导致出错
  • 对于这种类型的传引用,使用 const 修饰会更好,防止意外修改

关系运算符

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 Person {  
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
};

bool operator==(const Person & p)
{
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {
return true;
}
else {
return false;
}
}
string m_Name;
int m_Age;
};

// 调用
Person a("孙悟空", 18);
Person b("孙悟空", 18);
if(a == b)
else if(a != b)

函数调用运算符 ( )

1
2
3
4
5
6
7
8
9
10
class MyPrint {  
public:
void operator()(string text) {
cout << text << endl;
}
};

// 调用
MyPrint myFunc;
myFunc("hello world");
1
2
3
4
5
6
7
8
9
10
class MyAdd {  
public:
int operator()(int v1, int v2) {
return v1 + v2;
}
};

// 调用
MyAdd add;
int ret = add(10, 10);