今天看了B站中黑马视频中关于运算符重载的内容,只给自己一个算是复习的东西,如果有人想去更好的了解,建议去《黑马》——C++核心编程_漏网小鱼的博客-CSDN博客,我只是想复习一下,若侵权,请告知,会删。
运算符重载:
- 加号运算符重载
- 左移运算符重载
- 递增运算符重载
- 赋值运算符重载
- 关系运算符重载
- 函数调用运算符重载
平时我们所知道的“+”,“-”,"<","="等针对的都是C++中已知的数据类型,若自己定一个类即另一种数据类型,想要对类进行运算,那么编译器不知道该如何进行运算,这个时候就需要进行运算符重载。operator(运算符):即对运算符进行了重载,
1、加号运算符重载
两种实现方法:
1.1成员函数实现
Person p3 = p2 + p1; //相当于p2.operator+(p1);
1.2全局函数实现
也可以实现函数重载
Person p4 = p3 +10; //相当于operator+(p3,10);
2、左移运算符重载
左移运算符不可以通过成员函数进行实现,因为如当输出cout<<p时,当通过成员函数对左移运算符<<进行重载时,输入值为p,而在成员函数中本身就是p,发生矛盾,成员函数就是在本身的类即this中进行的操作,当有输入时,即变成了两个对象,而输出cout只有自身,所以只能通过全局函数实现。
ostream& operator<<(ostream& cout, Person& p){...}
cout的类型为输出流类型,即ostream,但全局中只能有一个cout,所以采用引用的方式进行输入,当cout<<p<<endl,里边有两个左移运算符(<<),即cout为一个链式输出,因此当左移运算符进行重载时,需要返回输出流cout,以保证能够链式传递。
当类为私有时,可以采用友元函数friend实现输出。
3、递增运算符重载
递增运算符有两种,++a和a++两种,++a为先进行加法运算在进行输出,a++为先输出在进行加法运算。采用成员函数实现,因为++存在前置和后置两种情况,因此在重载时采用占位参数来区分:
前置++:MyInteger& operator++(){},返回引用
由于要实现链式递增,需始终对一个对象操作,即返回一个引用。如:
cout<<++(++Myint)<<endl;
cout<<Myint<<endl;
如果返回的是值的话,当Myint初始值为0时,最终输出Myint为1,若返回引用的话,输出才是2。
后置++:Myinteger operator++(){},返回值
由于后置++需要先返回值,后递增,而如果先输出return时,不会进行后续的++操作,所以需要设置一个临时变量存储当前值,然后进行++,最后在返回临时变量的值,而临时变量(即局部变量)不能返回引用,局部变量在当前函数执行完之后被释放,不能返回地址。因此不存在(++Myint)++的情况,该情况下Myint只会增加一次,而不能实现链式相加。
由于前置++返回引用(即返回地址)而后置++返回值(需要创建临时变量),所以前置++比后置++省时,且前置++返回后的为加完之后的,所以前置++更常用。
4、赋值运算符重载
通过成员函数实现,当类中有属性指向堆区时,存在深浅拷贝问题。即内存重复释放问题。通过深拷贝解决浅拷贝问题。
当在构造函数中创建一个堆区进行数据管理时,在析构函数中进行释放,若进行赋值操作后,如p2=p1,两个所指的内存是一个。当p2的析构函数运行释放了该地址的内存后,p1运行析构函数时会再次释放该地址内存,造成内存重复释放,这就是浅拷贝的问题,如果想要解决该问题,需要将赋值运算符进行重载,编译器是直接赋值,即p2=p1,若p2本身存在初始值的时候,即先判断是否有属性在堆区,如果有先释放干净,然后在进行深拷贝,这样可以避免内存泄漏。进行深拷贝的时候给p2在单独开辟一块堆区内存,避免p1和p2内存一致。
5、关系运算符重载
通过重载关系运算符,对其他数据类型进行关系运算。
6、函数调用运算符重载
函数调用运算符即(),重载后使用方法特别像函数调用,因此称为仿函数,没有固定写法,非常灵活。在成员函数中使用,如:
void operator()(string text){}
int operator()(int v1,int v2){}
其中存在一种情况:匿名函数调用
匿名函数调用:
cout<<"MyAdd()(100,100)"<<MyAdd()(100,100)<<endl;
为:类名()()操作。