运算符重载概念:
对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
一般有+,左移,递增,赋值,关系函数调用这几种运算符重载
基本形式为
返回类型 operator @ (参数表)
(1)+运算符重载
person+int类型
```cpp
Person operator+(Person &p,int num)
{
Person temp;
temp.m_A=p.m_A+num;
temp.m_B=p.m_B+num;
return temp;
}
全局函数Person operator+(Person &p1,Person &p2)
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+person类型
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;
}
下面是实例
#include<iostream>
using namespace std;
class Person
{
public:
//成员函数重载+号 ,成员函数重载本质是Person p3=p1.operator+(p2)
/*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;
};
//全局函数重载本质是Person p3=operator(p1+p2)
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 &p,int num)
{
Person temp;
temp.m_A=p.m_A+num;
temp.m_B=p.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 p4=p3+100;//运算符重载也可以发生函数重载,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();
}
运行结果如图
(2)左移运算符重载
左移运算符重载有几点需要注意
cout<<p1<<"hello world"<<endl;
这是一个链式编程,输出p1之后需要返回值为cout类型,而cout的类型是ostream,所以需要使用 ostream& 进行重载
#include<iostream>
using namespace std;
class Person
{
friend ostream& operator<<(ostream& out,Person& p);
public:
Person(int a,int b)
{
this->m_A=a;
this->m_B=b;
}
private:
int m_A;
int m_B;
};
ostream& operator<<(ostream& out,Person& p )
{
out<<"a:"<<p.m_A<<" b:"<<p.m_B<<endl;
return out;
}
void test01()
{
Person p1(10,20);
cout<<p1<<"hello world"<<endl;
}
int main()
{
test01();
}
运行结果是
(3)递增运算符重载
前置++和后置++的区别
int a=10;
cout<<++a<<endl;//11
cout<<a<<endl;//11
int b=10;
cout<<b++<<endl;//10
cout<<b<<endl;//11
前置运算符返回的是指针,后置运算符返回的是数值,二者靠int区别
想输出类cout<<++myInt<<endl;还要用到左移运算符重载,全局函数声明
#include<iostream>
using namespace std;
class MyInteger
{
friend ostream& operator<<(ostream& out,MyInteger myint);
public:
MyInteger()
{
num=0;
}
//前置递增运算符++也写后面,靠(int)与后置区分
MyInteger& operator++()
{
num++;
return *this;
}
MyInteger operator++(int)
{
//保存
MyInteger temp=*this;
//进行++
num++;
// 返回保存的
return temp;
}
private:
int num;
};
ostream& operator<<(ostream& out,MyInteger myint)
{
out<<myint.num;
return out;
}
void test01()
{
MyInteger myInt;
cout<<++myInt<<endl;
cout<<myInt<<endl;
}
void test02()
{
MyInteger myInt;
cout<<myInt++<<endl;
cout<<myInt<<endl;
}
int main()
{
test01();
test02();
}
运行结果是
(4)赋值运算符重载
C++编译器至少给一个类添加4个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对属性进行值拷贝
4.赋值运算符operator=,对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
浅拷贝会带来堆区内存重复释放的问题,造成系统崩溃,这个问题就要用深拷贝解决,即开辟一块新的内存
对深浅拷贝不太了解的,可以看一下我之前写的文章深浅拷贝
下面是例子
#include<iostream>
using namespace std;
class Person
{
public:
Person(int age)
{
m_Age=new int(age);
}
//赋值运算符重载
//编译器提供的是浅拷贝,m_Age=p. m_Age
Person& operator=(Person &p)
{
if(m_Age!=NULL)//要先判断堆区内存是否释放干净
{
delete m_Age;
m_Age=NULL;
}
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();
}
运行结果如下
(5)关系运算符重载
关系运算符: <, > , ==, !=
#include<iostream>
using namespace std;
class Person
{
public:
Person(string name,int age)
{
m_Name=name;
m_Age=age;
}
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;
}
}
string m_Name;
int m_Age;
};
void test01()
{
Person p1("Tom",18);
Person p2("Tom",18);
if(p1==p2)
{
cout<<"p1和p2是相等的"<<endl;
}
else
{
cout<<"p1和p2是不相等的"<<endl;
}
if(p1!=p2)
{
cout<<"p1和p2是不相等的"<<endl;
}
else
{
cout<<"p1和p2是相等的"<<endl;
}
}
int main()
{
test01();
}
运行结果如下
(6)函数调用运算符重载()
·函数调用运算符()也可以重载
·由于重载后使用的方式非常像函数的调用,因此称为仿函数
·仿函数没有固定写法,非常灵活
#include<iostream>
using namespace std;
class MyPrint
{
public:
MyPrint(string name)
{
cout<<name<<endl;
}
};
void test01()
{
MyPrint p1("Tom");
}
class MyAdd
{
public:
int operator()(int a,int b)
{
return a+b;
}
};
void test02()
{
MyAdd add;
int ret=add(1,2);
cout<<"ret="<<ret<<endl;
cout<<MyAdd()(1,2)<<endl;//匿名对象调用
}
int main()
{
test01();
test02();
}
运行结果如下