目录
[4.5 运算符重载](#4.5 运算符重载)
[4.5.1 加号运算符重载](#4.5.1 加号运算符重载)
[4.5.2 左移运算符重载](#4.5.2 左移运算符重载)
[4.5.3 递增运算符重载](#4.5.3 递增运算符重载)
[4.5.4 赋值运算符重载](#4.5.4 赋值运算符重载)
[4.5.5 关系运算符重载](#4.5.5 关系运算符重载)
[4.5.6 函数调用运算符重载](#4.5.6 函数调用运算符重载)
4.5 运算符重载
运算符重载概念:
对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
4.5.1 加号运算符重载
作用:实现两个自定义数据类型相加的运算
cpp
#include <iostream>
using namespace std;
// 加号运算符重载
class Person {
public:
//1、成员函数重载+号
// Person operator+( Person& p) {
// Person temp;
// temp.m_A = m_A + p.m_A;
// temp.m_B = m_B + p.m_B;
// return temp;
// }
int m_A;
int m_B;
};
//2、全局函数重载+号
Person operator+( Person& p1, 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+( Person& p1, int num) {
Person temp;
temp.m_A = p1.m_A + num;
temp.m_B = p1.m_B + num;
return temp;
}
void test_1(){
Person p1, p2;
p1.m_A = 10;
p1.m_B = 20;
p2.m_A = 30;
p2.m_B = 40;
// 成员函数重载本质调用
// Person p3 = p1.operator+(p2);
// 全局函数重载本质调用
// Person p3 = operator+(p1, p2);
Person p3 = p1 + p2;
cout << "p3.m_A = " << p3.m_A << endl;
cout << "p3.m_B = " << p3.m_B << endl;
// 运算符重载,也可以发生函数重载
Person p4 = p1 + 100;
cout << "p4.m_A = " << p4.m_A << endl;
cout << "p4.m_B = " << p4.m_B << endl;
}
int main() {
test_1();
return 0;
}
总结1:对于内置的数据类型的表达式的的运算符是不可能改变的
总结2:不要滥用运算符重载
4.5.2 左移运算符重载
作用:可以输出自定义数据类型
cpp
#include <iostream>
using namespace std;
// 左移运算符重载
class Person {
friend ostream& operator<<(ostream& cout, Person& p);
public:
Person(int a, int b) {
m_A = a;
m_B = b;
}
private:
int m_A;
int m_B;
};
// 只能利用全局函数进行 左移运算符重载
ostream& operator<<(ostream& cout, Person& p) {
cout << "A: " << p.m_A << " B: " << p.m_B << endl;
return cout;
}
void test() {
Person p(10, 20);
cout << p << endl;
}
int main() {
test();
system("pause");
return 0;
}
总结:重载左移运算符配合友元可以实现输出自定义数据类型
4.5.3 递增运算符重载
作用:通过重载递增运算符,实现自己的整型数据
cpp
#include <iostream>
using namespace std;
// 递增运算符重载
// 自定义类
class MyInteger {
friend ostream& operator<<(ostream& os, MyInteger& myInt);
private:
int m_Num;
public:
MyInteger() {m_Num = 10;}
// 前置递增运算符重载
MyInteger& operator++() {
m_Num++;// 先自增,再返回引用
return *this;// 返回引用,以便可以连续使用++
}
// 后置递增运算符重载
MyInteger operator++(int) { // int代表占位参数用于区分前置和后置
MyInteger temp = *this;// 先拷贝一份副本,记录原值
m_Num++;// 后递增
return temp;// 返回临时对象,以便可以连续使用++
}
};
// 重载<<运算符
ostream& operator<<(ostream& os, MyInteger& myInt) {
os << "MyInteger: " << myInt.m_Num;
return os;
}
// 前置递增运算符重载测试
void test1() {
MyInteger myInt;
cout << "前置Before ++: " << ++myInt << endl;
cout << "前置After ++: " << myInt << endl;
}
// 后置递增运算符重载测试
void test2() {
MyInteger myInt;
cout << "Before ++: " << myInt++ << endl;
cout << "After ++: " << myInt << endl;
}
int main() {
test1();
test2();
system("pause");
return 0;
}
总结:前置递增返回引用,后置递增返回值
4.5.4 赋值运算符重载
C++编译器至少给一个类添加4个函数
- 1.默认构造函数(无参,函数体为空)
- 2.默认析构函数(无参,函数体为空)
- 3.默认拷贝构造函数,对属性进行值拷贝
- 4.赋值运算符 operator=,对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
示例:
cpp
#include <iostream>
using namespace std;
// 赋值运算符重载
class Person {
friend void test();// 声明test函数的友元
public:
Person(int age) {
m_Age = new int(age);
}
~Person() {
if (m_Age != nullptr) {
delete m_Age;
m_Age = nullptr;
}
}
// 赋值运算符重载
Person& operator=(const Person& p) {//const修饰符表示p是常量引用,不能修改p的值;
//编译器默认提供的赋值运算符是浅拷贝,即只拷贝指针,不会拷贝堆区的数据
//因此需要手动实现深拷贝
//m_Age = p.m_Age; // 直接赋值指针,不会拷贝堆区的数据
// 先判断是否有属性在堆区,如果有,先释放掉,再深拷贝
if (m_Age != NULL) {
delete m_Age;
m_Age = NULL;
}
m_Age = new int(*p.m_Age); // 利用指针的赋值运算符重载;深拷贝
return *this;// 返回对象本身
}
private:
int *m_Age;// 指向整数的指针
};
void test() {
Person p1(20);
Person p2(30);
Person p3(40);
p3 = p2 = p1; // 调用赋值运算符重载;赋值操作
cout << "p1 age: " << *p1.m_Age << endl;
cout << "p2 age: " << *p2.m_Age << endl;
cout << "p3 age: " << *p3.m_Age << endl;
}
int main() {
test();
system("pause");
return 0;
}
4.5.5 关系运算符重载
作用:重载关系运算符,可以让两个自定义类型对象进行对比操作
示例:
cpp
#include <iostream>
#include <string>
using namespace std;
// 重载关系运算符
class Person {
public:
Person(string name, int age) {
m_Name = name;
m_Age = age;
}
// 重载关系运算符
bool operator==(const Person& p) const {
return m_Name == p.m_Name && m_Age == p.m_Age;// 这里的 && 代表两个条件都满足才返回 true
}
bool operator!=(const Person& p) const {
return m_Name!= p.m_Name || m_Age != p.m_Age;// 这里的 || 代表两个条件有一个满足就返回 true
}
bool operator<(const Person& p) const {
return m_Age < p.m_Age;// 这里的 < 代表 p1.m_Age < p2.m_Age
}
bool operator>(const Person& p) const {
return m_Age > p.m_Age;// 这里的 > 代表 p1.m_Age > p2.m_Age
}
string m_Name;
int m_Age;
};
void test() {
Person p1("Tom", 20);
Person p2("Jerry", 25);
if (p1 == p2) {
cout << "p1 == p2" << endl;
}
if (p1!= p2) {
cout << "p1!= p2" << endl;
}
if (p1 < p2) {
cout << "p1 < p2" << endl;
}
if (p1 > p2) {
cout << "p1 > p2" << endl;
}
}
int main() {
test();
return 0;
}
4.5.6 函数调用运算符重载
- 函教调用运算符()也可以重载
- 由于重载后使用的方式非常像函数的调用,因此称为仿函数
- 仿函数没有固定写法,非常灵活
示例:
cpp
#include <iostream>
#include <string>
using namespace std;
// 函数调用运算符重载
// 打印输出类
class Printer {
public:
// 重载函数调用运算符
void operator()(string text) {
cout << text << endl;
}
};
void Printer_test(string text) {
cout << text << endl;
}
void test() {
Printer p;
p("Hello, world!");// 由于使用起来类似于函数调用,因此也称为 仿函数
Printer_test("Hello, world!");// 调用普通函数
}
// 仿函数非常灵活,没有固定写法
// 加法类
class Adder {
public:
int operator()(int a, int b) {
return a + b;
}
};
void test2() {
Adder a;
int result = a(10, 20);
cout << result << endl;
// 匿名函数对象
cout << "匿名函数对象: 10 + 20 = " << Adder()(10, 20) << endl;//
}
int main() {
test();
test2();
system("pause");
return 0;
}