2.5运算符重载
运算符重载:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
1、加号运算符重载
作用:实现两个自定义数据类型相加的运算。
1.成员函数重载+号
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; } public: int m_A; int m_B; }; void test() //测试函数 { Person p1(10, 20); Person p2(15, 25); //成员函数方式 Person p3 = p2.operator+(p1); //成员函数重载的本质调用 //Person p3 = p2 + p1; //简化后的调用方式 cout << "mA:" << p3.m_A << "; mB:" << p3.m_B << endl; } int main() { test(); return 0; }
2.全局函数重载+号
class Person { public: Person() {}; Person(int a, int b) { this->m_A = a; this->m_B = b; } public: int m_A; int m_B; }; //全局函数实现+号重载 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; } void test() { Person p1(10, 20); Person p2(15, 25); //全局函数方式 Person p4 = operator+(p1, p2); //全局函数重载的本质调用 //Person p4 = p1 + p2; cout << "mA:" << p4.m_A << "; mB:" << p4.m_B << endl; } int main() { test(); return 0; }
运算符重载也可以发生函数重载。
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; }
总结
总结1:对于内置的数据类型的表达式的运算符是不可以改变的;
编译器知道内置的数据类型的计算。
总结2:不要滥用运算符重载。
2、左移运算符重载
作用:可以输出自定义数据类型
通常不会利用成员函数重载<<运算符,因为无法实现cout在左侧。
只能利用全局函数来重载<<运算符。
class Person { friend ostream& operator<<(ostream& out, Person& p); public: Person(int a, int b) { this->m_A = a; this->m_B = b; } //成员函数 实现不了 p << cout 不是我们想要的效果 //void operator<<(Person& p){ //} private: int m_A; int m_B; }; //全局函数实现左移重载 //ostream对象只能有一个 为了实现链式编程,我们返回一个ostream的引用 ostream& operator<<(ostream& out, Person& p) { out << "a:" << p.m_A << " b:" << p.m_B; return out; } void test() { Person p1(10, 20); cout << p1 << "hello world" << endl; //链式编程 } int main() { test(); return 0; }
总结:重载左移运算符配合友元可以实现输出自定义数据类型
3、递增运算符重载
作用:通过重载递增运算符,实现自己的整形数据
class myInteger { friend ostream& operator<<(ostream& out, myInteger myint); public: //构造函数 myInteger() { m_Num = 0; } public: //重载前置++运算符 //返回引用是为了可以一直对一个数据进行递增操作 myInteger& operator++() { //先进行++运算 m_Num++; //再将自身做返回 return *this; } //重载后置++运算符 这个int是一个占位参数,用来区分,前置和后置函数,防止重定义 myInteger operator++(int) { //先记录当时的结果 myInteger temp = *this; //后递增 m_Num++; //最后将记录结果做返回 return temp; } private: int m_Num; }; //全局函数实现<<运算符重载 ostream& operator<<(ostream& out, myInteger myint) { out << myint.m_Num; return out; } //实现自定义++ void test() { myInteger myint1; cout << ++myint1 << endl; cout << myint1 << endl; cout << myint1++ << endl; cout << myint1 << endl; } int main() { test(); return 0; }
总结:前置递增返回引用,后置递增返回值
4、赋值运算符重载
C++编译器至少给一个类添加4个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对属性进行值拷贝
4.赋值运算符operator=,对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题。
class Person { public: Person(int age) //构造函数,初始化数据 { //将年龄数据开辟到堆区 m_Age = new int(age); } //重载赋值运算符 Person& operator=(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; } } //年龄的指针 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(); return 0; }
5、关系运算符重载
作用:重载关系运算符,可以让两个自定义类型对象进行对比操作。
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; } else { return false; } } bool operator!=(Person & p) { if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) { return false; } else { return true; } } string m_Name; int m_Age; }; void test01() { //int a = 0; //int b = 0; 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(); return 0; }
6、函数调用运算符重载
1.函数调用运算符()也可以重载。
2.由于重载后使用的方式非常像函数的调用,因此也称为仿函数。
3.仿函数没有固定的写法,非常灵活。
在后续STL的课程中会经常用到仿函数,会遇到各种各样的仿函数的写法。
目前了解。
class MyPrint { public: void operator()(string text) { cout << text << endl; } }; void test01() { //重载的()操作符 也称为仿函数 MyPrint myFunc; myFunc("hello world"); } class MyAdd { public: int operator()(int v1, int v2) { return v1 + v2; } }; 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(); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!