赋值运算符重载
说明
赋值运算符重载是用一个已经存在的对象,给另一个已经存在的对象赋值,两个对象均已创建结束后,发生赋值行为。
语法
格式固定:
类名
{
类名 & operator=(const 类名 & 源对象)
{
//拷贝体
return *this;
}
}
class A
{
A & operator=(const A & another)
{
//函数体
return *this;
}
};
特性
代码演示:
#include <iostream>
using namespace std;
struct Data
{
public:
Data(int y = 2016, int m = 6, int d = 6)
:year(y), month(m), day(d)
{}
void dis()
{
cout << " year " << year << " month " << month << " day " << day << endl;
}
private:
int year;
int month;
int day;
};
int main()
{
Data d(2018, 8, 8);
d.dis();
Data d2(2019, 9, 9);
d2 = d;
d2.dis();
return 0;
}
运行结果:
可以看到并没有自己写赋值运算符重载,但是确实赋值成功了,并且正确赋值。
进行说明:
系统默认提供的赋值运算符重载。也是一种浅赋值行为。
理解:
拷贝构造器和赋值运算符重载的区别,拷贝构造器是原来不存在直接进行构造一份,赋值运算符重载是本来就有两份,然后拿第一份的将第二份覆盖。
如果对象中不存在堆内存空间,此时系统默认提供的赋值运算符重载可以满足需求。如果对象中含有堆上的内存空间则需要自实现完成深拷贝。
格式语法固定。
一旦自实现,系统默认提供的赋值运算符重载将不存在。
如果自实现了但是里面没有内容,那么就不能实现赋值运算符重载:
#include <iostream>
using namespace std;
struct Data
{
public:
Data(int y = 2016, int m = 6, int d = 6)
:year(y), month(m), day(d), space(new char[1024])
{}
Data & operator = (const Data& another)
{
}
void dis()
{
cout << " year " << year << " month " << month << " day " << day << endl;
}
private:
int year;
int month;
int day;
char* space;
};
int main()
{
Data d(2018, 8, 8);
d.dis();
Data d2(2019, 9, 9);
d2 = d;
d2.dis();
return 0;
}
运行结果为:
可以看到赋值运算符没有重载成功。
自实现运算符重载:
#include <iostream>
using namespace std;
struct Data
{
public:
Data(int y = 2016, int m = 6, int d = 6)
:year(y), month(m), day(d), space(new char[1024])
{}
Data & operator = (const Data& another)
{
this->year = another.year;
this->month = another.month;
this->day = another.day;
return *this;
}
void dis()
{
cout << " year " << year << " month " << month << " day " << day << endl;
}
private:
int year;
int month;
int day;
char* space;
};
int main()
{
Data d(2018, 8, 8);
d.dis();
Data d2(2019, 9, 9);
d2 = d;
d2.dis();
return 0;
}
运行结果:
上面实例中实现的赋值运算符重载和系统默认提供的赋值运算符重载实现的结果是一样的。
为什么在运算符重里面加入了return * this
:
给出main函数中的代码,其他代码不变:
int main()
{
Data d(2018, 8, 8);
d.dis();
Data d2(2019, 9, 9);
d2 = d;
d2.dis();
//使用返回this指针
Data d3;
d3 = d2 = d; //与下面一行代码实现意义完全不相同
d3.operator=(d2.operator=(d));
return 0;
}
理解:d
赋值给d2
,整个表达式返回了d2
,然后d2
作为参数进行传递,将d2
赋值给d3
,整个表达式又返回d3
。
自实现存在的问题
重析构
在释放内存的时候就会出现重析构问题。
内存泄漏
解决:先把自己之前的内存进行释放,然后进行深拷贝。
自赋值
自赋值意思就是说当出现自己赋值给自己的时候,那么原来的内存空间被释放了,但是原来的内存空间里面还是自己本身,如果释放之后就无法进行赋值运算符重载,所以我们在自实现的是时候就要解决这个问题。
解决
代码实现:
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <iostream>
using namespace std;
struct Data
{
public:
Data(int y = 2016, int m = 6, int d = 6)
:year(y), month(m), day(d), space(new char[1024])
{}
Data& operator = (const Data& another)//赋值运算符重载
{
if (this == &another) //解决自赋值的问题
return *this; //实现链式表达
else
{
delete[]this->space; //解决内存泄漏的问题
space = new char[strlen(another.space) + 1];
strcpy(space, another.space);
}
year = another.year;
month = another.month;
day = another.day;
return *this;
}
~Data() //析构器
{
cout << "~~~~~~~~" << this << endl; //指向当前对象的指针
delete[]space;
}
void dis()
{
cout << " year " << year << " month "
<< month << " day " << day << endl;
}
private:
int year;
int month;
int day;
char* space;
};
int main()
{
Data d(2018, 8, 8);
d.dis();
Data d2(2019, 9, 9);
d2 = d;
d2.dis();
return 0;
}
上面自实现代码就解决了这三个问题。
运行结果:
接下来进行说明在:
Data & operator = (const Data & another)
进行传递的时候参数使用 const
的作用就是 another
里面的内容肯定不会修改。
那么 Data & operator = (const Data & another)
最前面没有引用,所以可以返回this
指针的内容,如果给最前面也加上const
。
const Data & operator = (const Data & another)
我们可以看到如果在返回引用的时候没有使用const
,返回之后可以被赋值。如果不想被赋值就在返回类型前面加上const
。
例如:(d3 = d2) = d;
如果前面有const
那么表达式不可以被赋值。