C++为了增加代码的可读性引入运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与普通的函数类似。
运算符重载即给某个运算符定义一个新的算法,让它能做原本不能做的运算。
运算符重载的关键字为operator,它的后面跟着你想重载的运算符,可以在类内重载,也可以在内外重载,像左移和右移运算符一般在类外重载,加减乘除可在类内重载。
1、加号重载
代码如下
Person operator+(Person &p1,int b){
Person temp;
temp.m_a=p1.m_a+b;
temp.m_b=p1.m_b+b;
return temp;
}
其中int b可以改为Person &p2或者其他,同时应在类中添加友元,后面的也都是。
2、左移/右移运算符重载
左移运算符即<<,它属于头文件iostream里面的ostream类。故代码应如下:
ostream &operator<<(ostream &cout,Person &p){
cout<<p.m_A<<" "<<p.m_B;
return cout;
}
为啥要用ostream作为返回值呢?我的理解是要连续输出,如果用void做返回值那么只能输出一次不能实现cout<<()<<()<<()<<…<<endl;的操作,即无法追加输出,只能实现cout<<对象;的操作
右移与之类似,只是ostream改为了istream,二者分别对应输出流和输入流。
3、递增/递减运算符重载
代码如下:
Person &operator++(Person &p){
p.m_A++;
return p;
}
Person operator++(Person &p,int){
Person temp=p;
p.m_A++;
return temp;
}
其中第一个是前置递增,第二个是后置递增。第二个要注意,一是要在参数列表里添加一个占位参数int,为什么呢?我在一篇博客上找到了答案:
重载主要是两者形参上的区别:
前置++没有形参,而后置++有一个int形参,但是该形参也没有被用到。很奇怪,难道有什么特殊的用意?
其实也没有特殊的用意,只是为了绕过语法的限制。
前置++与后置++的操作符重载函数,函数原型必须不同。否则就违反了“重载函数必须拥有不同的函数原型”的语法规定。
虽然前置++与后置++的返回类型不同,但是返回类型不属于函数原型。为了绕过语法限制,只好给后置++增加了一个int形参。
原因就是这么简单,真的没其他特殊用意。其实,给前置++增加形参也可以;增加一个double形参而不是int形参,也可以。只是,当时就这么决定了。
4、赋值运算符重载
赋值运算符重载我一般写在类里面,应为我写在类外总是会出现错误,阿巴阿巴,不管它啦。代码如下:
class Person {
public:
int *m_A;
Person(int a){
m_A=new int(a);
}
~Person(){
if(m_A!=NULL){
delete m_A;
m_A=NULL;
}
}
Person &operator=(Person p){
if(m_A!=NULL){
delete m_A;
m_A=NULL;
}
m_A=new int(*p.m_A);
return *this;
}
};
其实,由于编译器为我们提供了一份赋值运算符,如果我们不写编译器会自动调用它,但这样就会出现浅拷贝问题,即内存空间重复释放,但如果你不写析构函数也不会重复释放2333,但这样又会出现内存泄漏的问题,我们是严谨的程序猿,所以我们要自己写赋值运算符重载,这也就是深拷贝,在堆区new一块内存,这样就解决了重复释放的问题,这个东西在我的构造函数浅理解中也说到过,有兴趣的小伙伴可以看看呀。
5、关系运算符(==和!=)重载
代码如下:
//类内
bool operator==(Person &p){
if(this->m_age==p.m_age&&this->m_name==p.m_name)
return true;
else return false;
}
bool operator!=(Person &p){
if(this->m_age==p.m_age&&this->m_name==p.m_name)
return false;
else return true;
}
没啥好说的,记得用bool作为返回值。
6、函数调用运算符重载
函数调用运算符就是函数后面的那个(),由于他使用的时候很像函数调用,故而又称仿函数,仿函数的写法十分灵活,没有固定写法,下面给出一种示例:
class Myadd{
public:
int operator()(int a,int b){
return a+b;
}
};
void test02(){
Myadd m;
int ret=m(10,10);
int p=Myadd()(ret,ret);//匿名对象
cout<<ret<<endl;
cout<<p<<endl;
}
最后运算符重载不是想让什么重载就让什么重载比如:
. :成员访问运算符
. *, ->:成员指针访问运算符
:: :域运算符
sizeof :长度运算符
?: :条件运算符
#: 预处理符号
不能重载。
还有什么@啊啥啥的也不能重载,建议最好不要随意重载,比如加号重载为减号等等,要增加代码的可读性。
最后黄字转自:为什么后置++和后置–是单目运算符却有一个int形参