C++运算符重载
C++运算符重载
对于这个问题我们一般使用函数来解决,而编译器为我们提供了一个标准的命名方式可以简化调用方式,实现自定义数据类型的运算符使用,我们称其为运算符重载
关键字:operator+运算符
重载方式
成员函数重载(在类内)
全局函数重载(在全局区)
加号运算符重载
参考代码:
#include <iostream>//关键词 operator using namespace std; //运算符重载的概念:对已有的运算符重新定义,赋予其另一种功能,以适应不同的数据类型 //加号运算符重载 class Person { public: //1、成员函数重载+号 /*Person operator+(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; }; //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 test01() { Person P1; P1.m_A = 10; P1.m_B = 10; Person P2; P2.m_A = 10; P2.m_B = 10; //简化调用: Person P3 = P1 + P2; //成员函数重载本质调用: //Person P3 = P1.operator + (P2); //全局函数重载的本质调用: //Person P3 = operator+(P1, P2); //运算符重载,也可以发生函数重载 Person P4 = P1 + 10; //Person + int cout << "P3.m_A=" << P3.m_A << endl; cout << "P3.m_B=" << P3.m_B << endl; cout << "P4.m_A=" << P4.m_A << endl; cout << "P4.m_B=" << P4.m_B << endl; } int main() { test01(); system("pause"); return 0; }
左移运算符重载
参考代码:
#include <iostream> using namespace std; //可以输出自定义数据类型 class Person { friend ostream& operator<<(ostream &cout, Person &P); //全局函数做友元 public: //在定义一个默认构造函数初始化 Person() { m_A = 10; m_B = 10; } //更改一下public: private: //一般成员属性用私有权限(使用友元!) //利用成员函数来重载一个 << 运算符 //一开始使用:void operator<<(Person &P)时,调用时 P.opertor<<(P)显然不符合 //现在:简化版本 P << cout; 显然先后次序发生了变化(看不懂就参考一下 加号的 成员函数重载简化) //不会利用成员函数重载 << 运算符,因为无法实现 cout在左侧 /*void operator<<(cout) { }*/ int m_A; int m_B; }; //这个重载函数是没有返回值的 //只能利用全局运算符重载左移运算符 cout的数据类型可以通过查看定义来看 ostream& operator<<(ostream &cout, Person &P) //本质 operator<<(cout,P) 简化 cout << P { cout << "m_A = " << P.m_A << "m_B = " << P.m_B; return cout; //引用做函数返回值 函数调用可以作为左值 此处是为了进行链式追加 //最后注意:引用本身就是取别名,所以这里使用out也可以 } void test01() { Person P; //为了实现直接输出对象,而重载左运算符 cout << P << endl << "Hello world!" << endl; //想要链式追加? } int main() { test01(); system("pause"); return 0; }
递增运算符重载
#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; } //同一个作用域下 函数名一样 但是参数。。。 (返回值与函数重载无关) //重载后置++运算符 //这里只能够用 int 不能用其它数据类型 MyInteger operator++(int) //加上一个 占位参数,可以用于区分前置和后置递增 { //先 返回结果(但是直接return函数就会运行结束) //所以:先记录一下当时的结果 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; //myint是创建的一个对象 cout << ++(++myint) << endl; //此处需要实现myint的 左移位运算 与 自增运算 cout << myint << endl; //显然通过此行输出我们可以看出 //如果返回类型不是一个引用 那么就不是在同一个数据上进行这两次自增操作 } //后置递增 void test02() { MyInteger myint; cout << myint++ << endl; cout << myint << endl; } int main() { //前置 //test01(); //后置 test02(); //在内置的此类操作中 两次前置递增 都是在同一个数据上进行 /*int a = 0; cout << ++(++a) << endl; cout << a << endl;*/ system("pause"); return 0; }
递减运算符重载
参考代码:
#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的引用使其可以作为左值 { cout << myint.m_Num; //本身传入对象无法接收 这里就相当于构造了一个函数来传入对象中的可接受值 return cout; } //前置递减 void test01() { MyInteger myint; cout << --(--myint) << endl; //测试是否能够连续递增(链式编程追加) cout << myint << endl; } //后置递减 void test02() { MyInteger myint; cout << myint-- << endl; cout << myint << endl; } int main() { //test01(); test02(); system("pause"); return 0; }
赋值运算符重载
参考代码:
#include <iostream> using namespace std; //C++编译器至少给一个类添加4个函数 //1、默认构造函数(无参,函数体为空) //2、默认析构函数(无参,函数体为空) //3、默认拷贝函数,对属性进行值拷贝 //4、赋值运算符operator=,对属性进行值拷贝(也会和浅拷贝一样,引起堆区内存重复释放) //即:简单拷贝,会连着将地址值也拷贝到另一个对象里, //当我们提供的成员属性是堆区的地址时,需要借助析构函数进行内存释放,此时就会引起堆区内存的重复释放 //赋值运算符重载 class Person { public: Person(int age) { m_Age = new int(age); //用关键词 new 创建在了堆区 } ~Person()//堆区的内存重复释放 { if (m_Age != NULL) { delete m_Age; m_Age = NULL; } } //重载 赋值运算符 Person& operator=(Person &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; //此操作是为了连续赋值 } 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(); //对于内置数据类型支持连续赋值 /*int a = 10; int b = 20; int c = 30; c = b = a; cout << "a=" << a << endl; cout << "b=" << b << endl; cout << "c=" << c << endl;*/ system("pause"); return 0; }
关系运算符重载
参考代码:
#include <iostream> #include <string> using namespace std; //重载关系运算符 class Person { public: Person(string name, int age) { m_Name = name; m_Age = age; } //重载 == 号 bool operator==(Person &P) { if (P.m_Age == this->m_Age&&P.m_Name == this->m_Name) { return true; } else { return false; } } //重载 != 号 bool operator!=(Person &P) { if (P.m_Age != this->m_Age || P.m_Name != this->m_Name) { return true; } else { return false; } } string m_Name; int m_Age; }; //测试 == 的重载 void test01() { Person P1("张三", 18); Person P2("张三", 18); if (P1 == P2) { cout << "P1与P2是相等的" << endl; } else { cout << "P1与P2是不相等的" << endl; } } //测试 != 的重载 void test02() { Person P1("张三", 18); Person P2("张三", 18); if (P1 != P2) { cout << "P1与P2不是相等的" << endl; } else { cout << "P1与P2是相等的" << endl; } } int main() { test01(); test02(); system("pause"); return 0; }
函数调用运算符重载
参考代码:
#include <iostream> #include <string> using namespace std; //函数调用运算符 () 重载 //由于重载后使用的方式非常像函数的调用,因此成为仿函数 //仿函数没有固定的写法,非常灵活 (在后续的STL里面涉及的多) //打印输出类 class MyPrint { public: //重载函数调用运算符 //成员函数重载 void operator()(string test) { cout << test << endl; } }; void MyPrint02(string test) { cout << test << endl; } void test01() { MyPrint myPrint; myPrint("hello world"); //重载过后一个对象进行调用 由于使用起来非常类似一个函数调用,因此称为仿函数 MyPrint02("hello world"); //一个函数调用 } //仿函数非常灵活,没有固定的写法 //加法类 class MyAdd { public: int operator()(int num1,int num2) //比较两个仿函数的写法 形式不是唯一的(参数个数与返回值等) { return num1 + num2; } }; void test02() { MyAdd myadd; int ret = myadd(100, 100); cout << "ret = " << ret << endl; //匿名函数对象 //回忆匿名对象 MyAdd() 等价于 本类的对象名 //因此处重载了()使得这个匿名对象进行了仿函数调用 所以称其为匿名函数对象 cout << MyAdd()(100, 100) << endl; //先创建一个对象执行后直接释放(参考构造函数的调用) } int main() { //test01(); test02(); system("pause"); return 0; }
本文作者:如此而已~~~
本文链接:https://www.cnblogs.com/fragmentary/p/16415800.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步