运算符重载
运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
1.加号运算符重载
下面的程序实现两个自定义数据类型进行相加的运算
#include"iostream"
using namespace std;
class Person
{
public:
int pa;
int pb;
//类函数成员做函数重载
Person operator +(Person &p)
{
Person temp;
temp.pa=this->pa+p.pa;
temp.pb=this->pb+p.pb;
return temp;
}
};
//运算符重载也可以发生函数重载
Person operator+(Person &p1,int num)
{
Person temp;
temp.pa=p1.pa+num;
temp.pb=p1.pb+num;
return temp;
}
//全局函数做函数重载
/*Person operator+(Person &p1,Person &p2)
{
Person temp;
temp.pa=p1.pa+p2.pa;
temp.pb=p1.pb+p2.pb;
return temp;
}*/
void test()
{
Person p1;
p1.pa=10;
p1.pb=10;
Person p2;
p2.pa=10;
p2.pb=10;
Person p3;
//类成员函数做函数重载,下面这一行就是类成员函数做函数重载的原型
// p3=p1.operator+(p2);
//全局函数做函数重载, 下面这一行就是全局函数做函数重载的原型
// p3=operator+(p1,p2);
p3=p1+p2;
cout<<"p3.pa="<<p3.pa<<endl;
cout<<"p3.pb="<<p3.pb<<endl;
//运算符重载也可以发生函数重载
p3=p1+100; //Person + num
cout<<"p3.pa="<<p3.pa<<endl;
cout<<"p3.pb="<<p3.pb<<endl;
}
int main()
{
test();
return 0;
}
2.左移运算符重载
实现左移函数重载需要注意的是,不能利用成员函数重载左移运算符,因为无法实现cout在左侧。利用成员函数重载左移运算符的样子如右 p.operator<<(cout) 简化后 p<<cout
#include"iostream"
using namespace std;
class Person
{
//这里友元的原因就是 我们把数据成员设置为了私有成员
//为了在类外能够成功的访问类内私有成员,我们就采取了友元
friend ostream& operator <<(ostream &cout,Person &p);
private:
int pa;
int pb;
public:
void csh(int a,int b)
{
pa=a;
pb=b;
}
};
//左移运算符的重载 只能通过全局函数去重载
ostream& operator <<(ostream &cout,Person &p)
{
cout<<"p.pa="<<p.pa<<" "<<"p.pb="<<p.pb<<endl;
return cout;
}
void test()
{
Person p1;
p1.csh(10,10);
// operator<<(cout,p);
cout<<p1<<endl;
}
int main()
{
test();
return 0;
}
3.递增运算符重载
作用:通过重载递增运算符,实现自己的整型数据,下面的程序实现++x,程序中用到了一个左移重载为了就是我们在给变量进行++的时候可以用类的对象代替它全部的属性。
#include"iostream"
using namespace std;
class myint
{
friend ostream & operator<<(ostream &cout,myint &m);
public:
//重置前置++运算符,返回引用是为了我们在一直给一个数据进行++
//因为引用的作用就是说明我们无论进行多少次的++,都是对应一个地址进行的
myint& operator++()
{
//因为左移的重载我们调用对象的时候其实就是调用类内的这个成员属性
++pa;
//这里我们给哪个对象++,就返回谁。
return *this;
}
myint()
{
pa=0;
}
private:
int pa;
};
//左移重载,这样做的目的可以在输出时输出的对象就能够代替输出类内的数据成员
ostream & operator<<(ostream &cout,myint &m)
{
cout<<m.pa;
return cout;
}
//前置递增测试函数体
void test()
{
myint m_int;
cout<<++(++m_int)<<endl;
}
int main()
{
//前置递增
test();
return 0;
}
4.赋值运算符重载
在之前学习C++的文章中,曾经说过,当我们在类内什么都不定义的时候,我们编译器至少会给我们一个构造函数一个析构函数以及一个拷贝构造函数,除了这三个以外系统还至少给我们一个赋值运算符operator=,对属性进行值拷贝。除此之外我们在进行赋值运算符重载后进行赋值操作的时候,如果我们类中的属性有指向堆区的,在做赋值运算也是会同样出现深浅拷贝的问题,这个问题之前解释过。
#include"iostream"
using namespace std;
class Person
{
public:
Person(int a)
{
age=new int(a);
}
int *age;
~Person()
{
if(age!=NULL)
{
delete age;
age=NULL;
}
}
//这里运用引用是为了返回的是我们自己的值本身
Person& operator=(Person &p)
{
//我们要通过深拷贝的方法解决浅拷贝的问题
//被赋值对象可能在堆区存在着一定的数据,因此我们要对其进行释放
if(this->age!=NULL)
{
delete this->age;
age=NULL;
}
//int后面括号是里面的值是赋值还是给与前者开辟多大的空间呢
this->age=new int(*p.age);
//为了能够重复赋值 我们应该返回对象本身
return *this;
}
};
void test()
{
Person p1(18);
Person p2(20);
Person p3(22);
//直接赋值 其实采用的就是系统的默认拷贝构造函数 浅拷贝
p3=p2=p1;
cout<<"p1.age="<<*p1.age<<endl;
cout<<"p2.age="<<*p2.age<<endl;
cout<<"p3.age="<<*p3.age<<endl;
}
int main()
{
test();
return 0;
}
5.关系运算符重载
作用:重载关系运算符,可以让两个自定义类型对象进行对比操作,通俗的说就是对==和!=进行简单的运算符重载
#include"iostream"
using namespace std;
class Person
{
public:
int age;
Person(int a)
{
this->age=a;
}
bool operator==(Person &p)
{
if(this->age==p.age)
{
return true;
}
else
return false;
}
bool operator!=(Person &p)
{
if(this->age!=p.age)
{
return true;
}
else
return false;
}
};
void test()
{
Person p1(18);
Person p2(19);
cout<<"通过==去判断两个对象是否相等"<<endl;
if(p1==p2)
{
cout<<"二者相等"<<endl;
}
else
{
cout<<"二者不相等"<<endl;
}
cout<<"通过!=去判断两个对象是否相等"<<endl;
if(p1!=p2)
{
cout<<"二者不相等"<<endl;
}
else
{
cout<<"二者相等"<<endl;
}
}
int main()
{
test();
return 0;
}
6.函数调用运算符重载
<1>函数调用()也可以重载
<2>由于重载后使用的方式非常像函数的调用,因此称为仿函数
<3>仿函数没有固定的写法,非常灵活。
#include"iostream"
#include"string.h"
using namespace std;
class MyPrint
{
public:
void operator()(string test)
{
cout<<test<<endl;
}
};
//测试通过运算符重载的()
void test()
{
MyPrint myprint;
myprint("hello world!");
}
//系统调用
void test1(string test)
{
cout<<test<<endl;
}
int main()
{
//下面的两个测试主函数 一个是运算符测试 一个是函数调用
//通过运算符重载实现函数的调用
test();
test1("hello world!");
return 0;
}