1.运算符重载
1.1运算符重载的定义
运算符的定义要用到一个关键字operator,那么这个定义的格式就是operator+运算符号+(参数列表)+函数主体+返回值,如下图所示
1.2运算符重载的概念
我们要确定一个概念,就是对象之间是可以使用运算符的,但是当运算符用于对象之间时,会调用对应的运算符重载,如果没有用于对象之间的这个运算符重载,编译器就会报错。
1.3运算符重载参数个数问题
运算符重载参数个数可以参考运算符的参数个数,比如
==有两个参数,A==B,
++有一个参数,A++
-有两个参数 A-B : 在左边就给左边参数,在右边就给右边参数
1.4当运算符重载是成员函数
假如我在类中加一个private
那我们只能将运算符重载归到类中才能对private进行访问
为什么这样会报错呢?
因为C++在设计的时候,类中的成员函数第一个运算对象默认传给this指针,所以上面的D1可以不用写,编译器会将它传给this指针
但是我们也要注意了,在引用那个值的时候我们不能再用结构体变量名称引用了,我们需要用this指针去指向那个值
1.5重载运算符的优先级和结合性与对应运算符保持一致
1.6不能通过连接语法中没有的符号来创建新的运算符
比如operator¥,“¥”这种的符号的运算符根本没有
1.7有些运算符不能进行重载
比如 .* 和 :: 和 sizeof 和 ?: 和 .
上面5个运算符不能进行重载
1.8重载运算符至少有一个类类型的参数
像如果我们定义一个这样的重载运算符,编译器就会报错
1.9前置类型++和后置类型++的区分
当我们要定义前置类型++和后置类型++时,我们的重载运算符都是operator++
不能区分开来,那么C++就设计了区分的方式
如果是后置++那么就在设置重载时再加一个int形参
如果是前置++那么就不需要加int形参
2.赋值运算符重载
1.赋值运算符重载的应用
赋值重载运算符的符号是=
赋值运算符重载和拷贝函数的功能类似都是将一个对象的数据拷贝到另外一个数据、
区别是赋值运算符重载是对两个已有的对象进行拷贝
拷贝函数是用一个已有的对象去初始化另外一个对象
建议将赋值运算重载函数的被拷贝参数加const,以防这个参数被修改
还有就是将赋值运算重载函数的返回值定义为类类型,方便进行多重赋值
2.赋值重载运算符的一些性质
当我们不去定义赋值重载运算符时,编译器会自动生成一个默认的赋值重载运算符,
这个默认的赋值重载运算符的拷贝是一个字节一个字节去拷贝的
所以对于类里面全是内置类型的对象,默认赋值重载运算符就可以解决问题,对于自定义类型,当要进行赋值时,编译器会自动调用它自己的赋值重载运算符。
但是当对象中存在向系统申请资源时,默认的赋值重载就不太能解决问题了,我们来测试一下
看上面代码我们来测试一下如下图
你们看d2和d3的所有的变量都一致
但是代码运行结束的结果却是
造成这种现象的原因是因为d2和d3的arr指针都指向同一块区域,当d3结束调用析构函数时便会释放这块区域的数据, 然后d2结束调用它的析构函数时又会对这块区域释放数据,那么这块数据就释放了两次,所以当我们的内置类型有对系统申请资源的情况我们就要自己定义赋值重载运算符,
那么我们就要用到memcpy这个函数
如下代码
#include<iostream>
using namespace std;
class stack
{
public:
stack& operator=(const stack& S1)
{
memcpy(this->arr, &S1, sizeof(int) * capacity);
this->capacity = S1.capacity;
this->top = 0;
return *this;
}
stack(int n=10)
{
arr = (int*)malloc(sizeof(int) * n);
if (arr == NULL)
{
perror("malloc");
return;
}
capacity = 10;
top = 0;
}
~stack()
{
free(arr);
capacity = 0;
top = 0;
}
private:
int* arr;
int capacity;
int top;
};
int main() {
stack d2;
stack d3;
d3 = d2;
return 0;
}
这种方式的赋值重载运算符就不会发生错误
总结一下,当对象中没有对系统进行资源申请,那么编译器自动生成的赋值重载运算符就够用,如果有对系统进行资源申请,那么就需要我们自己定义赋值重载运算符。