即:对已有的运算符重新进行定义,富裕其另外一种功能,以适应不同的类型运算
加法(减法)运算法重载
比如 加法 + ,基本的类型,int,float等,编译器是知道如何计算的。
但是,对于自定义类或者其他高级点的类型时,编译器就不知道“+”运算法该如何操作了,这是就可以使用运算法重载的操作。
- 通过成员函数重载 + 号
class Person
{
public:
//成员函数重载+号
Person operator+(Person &a)
{
Person temps;
temps.m_A = this->m_A + a.m_A;
temps.m_B = this->m_B + a.m_B;
return temps;
}
int m_A;
int m_B;
};
void test()
{
Person p1;
Person p2;
p1.m_A = 10;
p2.m_A = 10;
p1.m_B = 10;
p2.m_B = 10;
//成员函数重载本质运行:
Person p3 = p1.operator+(p2);
//简化
Person p4 = p1 + p2;
}
- 通过全局函数重载 + 号
class Person
{
public:
//成员函数重载+号
/*Person operator+(Person &a)
{
Person temps;
temps.m_A = this->m_A + a.m_A;
temps.m_B = this->m_B + a.m_B;
return temps;
}*/
int m_A;
int m_B;
};
Person operator+(Person &a, Person &b)
{
Person tempss;
tempss.m_A = a.m_A + b.m_A;
tempss.m_B = a.m_B + b.m_B;
return tempss;
}
void test()
{
Person p1;
Person p2;
p1.m_A = 10;
p2.m_A = 10;
p1.m_B = 10;
p2.m_B = 10;
//成员函数重载本质运行:
//Person p3 = p1.operator+(p2);
//简化
//Person p4 = p1 + p2;
//全局函数重载本质:
Person p5 = operator+(p1, p2);
//简化
Person p6 = p1 + p2;
}
- 符号进行函数重载
Person operator+(Person &a,int num)
{
Person tempss;
tempss.m_A = a.m_A + num;
tempss.m_B = a.m_B + num;
return tempss;
}
左移运算法重载 <<
同样可以分为,成员函数重载 和 全局函数重载
一般 不用 成员函数重载 左移运算法
一般 采用 全局函数重载 左移运算法
class Person
{
public:
int M_A;
int M_B;
};
//重载左移运算法
ostream & operator<<(ostream &cout, Person &p)
{
cout << "" << p.M_A << "" << p.M_B;
return cout;
}
void test()
{
Person p;
p.M_A = 10;
p.M_B = 10;
cout << p << endl;
}
关于这个部分需要详细说明一下:
//重载左移运算法
ostream & operator<<(ostream &cout, Person &p)
{
cout << "" << p.M_A << "" << p.M_B;
return cout;
}
cout 在编译器中的标准定义中没有输出 类 的功能,所以对其进行重载,而全局函数涉及到对 cout 的新定义,从 std 定义中可以看到,cout 本身属于 ostream 类型,并采用 引用创新的名,防止重名,采用ostream 作为返回类型,采用引用,就是为了对最初的那个cout进行操作,如果不加&,它就会返回一个新的,所以采用 &这样 使用 endl 就不会报错了。
针对 类的私有变量的操作,可以配合友元函数进行操作:
#include <iostream>
using namespace std;
class Person
{ //使重载函数变成友元
friend ostream & operator<<(ostream &cout, Person &p);
public:
Person(int a, int b)
{
M_A = a;
M_B = b;
}
private:
int M_A;
int M_B;
};
//重载左移运算法
ostream & operator<<(ostream &cout, Person &p)
{
cout << "" << p.M_A << "" << p.M_B;
return cout;
}
void test()
{
Person p(10,10);
cout << p << endl;
}
递增运算法重载 ++
#include <iostream>
using namespace std;
class Person
{
//使重载函数变成友元
friend ostream & operator<<(ostream &cout, Person &p);
public:
Person(int a, int b)
{
M_A = a;
M_B = b;
}
//前置重载递增运算法,对自身属性进行操作不需要参数
//为啥使用 & , 这是为了当进行多次递增时,重载的对象都是最初的那个,如果不加&,会出现,没进行一次操作就又创建一个新的对象的情况
Person& operator++()
{
M_A++;
return *this;//返回类本身
}
private:
int M_A;
int M_B;
};
//重载左移运算法
ostream & operator<<(ostream &cout, Person &p)
{
cout << "" << p.M_A << "" << p.M_B;
return cout;
}
void test()
{
Person p(10,10);
cout << ++p << endl;
}
- 前置重载递增运算法,对自身属性进行操作不需要参数
- 为啥使用 & , 这是为了当进行多次递增时,重载的对象都是
最初的那个
,如果不加&,会出现,没进行一次操作就又创建一个新的对象的情况 》》链式编程
Person& operator++()
{
M_A++;
return *this;//返回类本身
}
- 重载后置 ++ 运算
- 这里加上 int 采用,int 作为占位参数,可以用于区分前置和后置
- 后置递增就是:
先
: 记录当前结果;后
递增;最后
记录结果返回- 这里不能使用 引用 &,因为本身后置递增时返回的是递增前的数值,就是说函数返回是递增前的数值,如果使用了引用 ,引用改变了,原来的数值也会改变,所以不符合后置递增的思想
//后置递增
Person operator++(int) //使用 int 作为占位参数,用于让编译器区分后置还是前置
{
Person temp = *this;//先记录当前值
M_B++;//在进行递增
return temp;//最后返回原来值
}
//全局函数:此时返回变量
ostream & operator<<(ostream &out, Person xx)
{
out << xx.M_B;
return out
}
需要注意,如果使用前面的 的左移运算的重载ostream & operator<<(ostream &out, Person &p)
在输出后置递增时,就不能直接使用 cout << p++<< endl;
,因为返回类型不同,一个返回的是引用,一个返回是的变量
赋值运算符重载 =
C++ 编译器至少提供给我们的四个函数:
- 构造函数
- 析构函数
- 拷贝构造函数
- 赋值运算符 operator= (但是这个操作就是见到的浅拷贝操作,释放堆区时还是会出现浅拷贝的问题)
所以可以通过重载来对 = 进行深拷贝的操作。
//赋值运算符重载
class Temp
{
friend void test2();
public:
Temp(int a)
{
m_A = new int(a);
}
~Temp()
{
if (m_A !=NULL)
{
delete(m_A);
m_A = NULL;
}
}
//返回引用还是为了应对对此赋值
Temp& operator=(Temp &p)
{
//深拷贝操作
this->m_A = new int(*p.m_A);
return *this;
}
private:
int *m_A;
};
void test2()
{
Temp T1(10);
Temp T2(20);
Temp T3(30);
T3 = T2 = T1;//赋值
cout << *T1.m_A << " " << *T2.m_A << " " << *T3.m_A << endl;
}
int main()
{
test2();
}
关系运算符重载 ==, !=,>,<, >=,<=等
//重载关系运算符
//赋值运算符重载
class Temp
{
friend void test2();
public:
Temp(int a)
{
m_A = new int(a);
}
~Temp()
{
if (m_A !=NULL)
{
delete(m_A);
m_A = NULL;
}
}
//重载关系运算符
bool operator==(Temp &T)
{
if (this->m_A == T.m_A)
{
return true;
}
else
{
return false;
}
}
//返回引用还是为了应对对此赋值
Temp& operator=(Temp &p)
{
//深拷贝操作
this->m_A = new int(*p.m_A);
return *this;
}
private:
int *m_A;
};
函数调用运算符重载 ()
class Temp
{
public
//重载 括号(),也就是仿函数,还可以有返回类型
void operator()(string str)
{
cout << str << endl;
}
}
void test3()
{
Temp P;
P("hello world");
}
重载 对 自定义类型 强制转换
class Fraction
{
public:
Fraction(int num, int den=1): m_numberator(num), m_denominator(den){}
//重载了对自定义类型的double()操作,const,看情况加,强制转换这里不需要有返回值类型,返回值类型就是double这里
operator double() const {
return (double)(m_numberator /m_denominator);
}
private:
int m_numberator;
int m_denominator;
};
....
Fraction f(3,5);
double d = 4 + f;//此时f就是返回0.6