15 运算符重载
运算符重载:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
运算符重载的本质是函数,函数名是 operator 加运算符符号。
15.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 40 41 42 43 44 45 46
| #include <iostream> using namespace std;
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; }
int m_A; int m_B; };
void test01() { Person p1(10, 10); Person p2(20, 20);
Person p3 = p1 + p2; cout << "p3.m_A = " << p3.m_A << " p3.m_B = " << p3.m_B << endl; }
int main() {
test01();
system("pause");
return 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 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
| #include <iostream> using namespace std;
class Person { public:
Person() {};
Person(int a, int b) { this->m_A = a; this->m_B = b; }
int m_A; int m_B; };
Person operator+(const Person& p1, const Person& p2) { Person temp; temp.m_A = p1.m_A + p2.m_A; temp.m_B = p1.m_B + p2.m_B; return temp; }
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; }
void test() { Person p1(10, 10); Person p2(20, 20);
Person p3 = p1 + p2; cout << "p3.m_A = " << p3.m_A << " p3.m_B = " << p3.m_B << endl;
Person p4 = p1 + 100; cout << "p4.m_A = " << p4.m_A << " p4.m_B = " << p4.m_B << endl; }
int main() {
test();
system("pause");
return 0; }
|
总结:
- 对于内置的数据类型的表达式的运算符是不可能改变的
- 不要滥用运算符重载
15.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 47 48
| #include <iostream> using namespace std;
class Person { friend ostream& operator<<(ostream& out, const Person& p);
public:
Person(int a, int b) { this->m_A = a; this->m_B = b; }
private:
int m_A; int m_B; };
ostream& operator<<(ostream& out, const Person& p) { out << "m_A = " << p.m_A << " m_B = " << p.m_B; return out; }
void test() { Person p1(10, 10);
cout << p1 << endl;
}
int main() {
test();
system("pause");
return 0; }
|
注意:
- 重载左移运算符配合友元,可以实现输出自定义数据类型
- 左移运算符重载只能用全局函数实现,不能用成员函数,因为成员函数要求调用对象在左,无法实现
cout << p
15.3 递增运算符重载
作用:通过重载递增运算符,实现自定义类型数据的自增运算。
- 前置递增:
++p 返回引用,是对同一个对象自增 - 后置递增:
p++ 返回值,是自增之前的拷贝
示例:
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 68
| #include <iostream> using namespace std;
class MyInteger { friend ostream& operator<<(ostream& cout, MyInteger& myint);
public:
MyInteger() { m_Num = 0; }
MyInteger& operator++() { m_Num++; return *this; }
MyInteger operator++(int) { MyInteger temp = *this; m_Num++; return temp; }
private:
int m_Num; };
ostream& operator<<(ostream& cout, MyInteger& myint) { cout << myint.m_Num; return cout; }
void test01() { MyInteger myInt;
cout << myInt << endl; cout << ++myInt << endl;
MyInteger myInt2;
cout << myInt2 << endl; cout << myInt2++ << endl; }
int main() {
test01();
system("pause");
return 0; }
|
总结:前置递增返回引用,后置递增返回值,这是为了保持与内置类型一致的行为。
15.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 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
| #include <iostream> using namespace std;
class Person { public:
Person(int age) { m_Age = new int(age); }
~Person() { if (m_Age != NULL) { delete m_Age; m_Age = NULL; } }
Person& operator=(Person& p) {
if (m_Age != NULL) { delete m_Age; m_Age = NULL; }
m_Age = new int(*p.m_Age);
return *this; }
int* m_Age; };
void test01() { Person p1(18); Person p2(20); Person p3(30);
p3 = p2 = p1;
cout << "p1的年龄为: " << *p1.m_Age << endl; cout << "p2的年龄为: " << *p2.m_Age << endl; cout << "p3的年龄为: " << *p3.m_Age << endl; }
int main() {
test01();
system("pause");
return 0; }
|
总结:如果类中有属性指向堆区,做赋值操作时一定要做深拷贝,否则会出现内存重复释放的问题。
15.5 关系运算符重载
作用:重载关系运算符,可以让两个自定义类型对象进行对比操作。
示例:
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 68 69
| #include <iostream> using namespace std;
class Person { public:
Person(string name, int age) { this->m_Name = name; this->m_Age = age; }
bool operator==(Person& p) { if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) { return true; } return false; }
bool operator!=(Person& p) { if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) { return false; } return true; }
string m_Name; int m_Age; };
void test01() { Person a("孙悟空", 18); Person b("孙悟空", 18);
if (a == b) { cout << "a和b相等" << endl; } else { cout << "a和b不相等" << endl; }
if (a != b) { cout << "a和b不相等" << endl; } else { cout << "a和b相等" << endl; } }
int main() {
test01();
system("pause");
return 0; }
|
15.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 43 44 45 46 47 48 49 50
| #include <iostream> using namespace std; #include <string>
class MyPrint { public:
void operator()(string text) { cout << text << endl; } };
class MyAdd { public:
int operator()(int v1, int v2) { return v1 + v2; } };
void test01() { MyPrint myFunc; myFunc("hello world"); }
void test02() { MyAdd add; int ret = add(10, 10); cout << "ret = " << ret << endl;
cout << "MyAdd()(100, 100) = " << MyAdd()(100, 100) << endl; }
int main() {
test01(); test02();
system("pause");
return 0; }
|
总结:函数调用运算符重载让对象的行为像函数,这种对象称为仿函数,在 STL 中会大量遇到。