【C++】运算符重载2-深拷贝深赋值、前加加后加加的重载

深拷贝、深赋值

我们首先通过下面这段代码来研究一下深拷贝和浅拷贝,区分一下什么时候需要我们自己来写拷贝构造函数和赋值运算符重载的函数。

class Test
{
private:
	int m_a = 1;
	int m_b = 2;
	int m_c = 3;
};
void main()
{
	Test t;
	Test t1 = t;
	Test t2;
	t2 = t1;
}

当类的成员是上面这种没有指针的,赋值直接取的是数值的情况时,类的默认成员函数可以满足我们的基本需求,例如,如果你想完成拷贝构造、赋值语句,可以直接用默认的,这种情况下是浅拷贝,我们仅仅是取值再赋值而已。
但是遇到下面这种类成员变量是指针类型的时候,情况就不一样了。

#include<iostream>
using namespace std;
class String
{
public:
	String(const char* str = "\0")
		//字符串常量要用常指针,要加const
	{
		m_data = (char*)malloc(strlen(str) + 1);//深拷贝
		//开辟空间要考虑字符串结束标志\0,所以要加一
		strcpy(m_data, str);
	}

	String(const String &s)
	{
		m_data = (char*)malloc(strlen(s.m_data) + 1);
		strcpy(m_data, s.m_data);
	}
	String& operator=(const String &s)
	{
		if (this != &s)
		{
			free(m_data);//深赋值
			m_data = (char*)malloc(strlen(s.m_data) + 1);
			strcpy(m_data, s.m_data);
		}
		return *this;
	}
	~String()
	{
		free(m_data);
	}
private:
	char *m_data = nullptr;
};
int main()
{
	String s("Hello");
	String s1 = s;
	String s2;
	s2 = s;
	return 0;
}

上面字符串类的成员变量是指针时,我们在进行“m_data = s.m_data”时,给m.data的是一个地址,如果是整形的话,那就可以进行浅拷贝,但是这种给地址的,就不能进行浅拷贝,要进行深拷贝。
地址指向的是某一个空间,如果仅仅浅拷贝传递地址值,那么将会造成两个指针指向同一个地址空间,这个时候也会造成在析构的时候,一个地址空间要被free掉两次,引起程序崩溃。同时,我们实例化出一个对象,希望能够拥有一个新的空间,但简单的浅拷贝不能满足我们的需求,我们就得申请一段空间,让m_data指向新的空间,那怎么完成空间地址值的传递呢?就用到了strcpy函数,这种新开辟一段空间,传递地址所指向空间的内容的拷贝,被称为深拷贝。
当有指针的成员变量存在时,基本都得考虑使用深拷贝和深赋值。
针对赋值运算符的重载我们解释几点:

free(m_data);

首先就是为什么要加这句话,它是为了防止内存泄漏的,因为是赋值语句,所以前提是等号两侧都已经有了空间,此时我们被赋值的m_data有自己的空间,而且空间可能还有值,m_data 和 s.m_data的空间大小很可能不一样,我们也不能直接申请新的空间,然后让m_data指向新的空间,这样子就引起内存泄漏了,所以我们需要先把m_data此时此刻指向的空间给它释放掉。

#include<iostream>
using namespace std;
class Time
{
public:
	Time()
	{
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Data
{
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};
int main()
{
	Data data;
	return 0;
}

C++把类型分为内置类型和自定义类型,内置类型就是语法已经定义好了的类型,自定义类型就是我们使用class/struct/union自己定义的类型,上面这段代码主要想表达的就是编译器生成的默认的构造函数会调用自定义类型成员的默认成员函数。

	Int c1 = a.Add(b);  //c1 = a + b;
	Int c2 = a.Sub(b);  //c2 = a - b;
	Int c3 = a.Mul(b);  //c3 = a * b;
	Int c4 = a.Div(b);  //c4 = a / b;

通过上面的代码,我们很明显能看出来右侧代码比左侧代码可读性强很多,因为右侧采用了运算符重载,赋予了“+”更多的意义。
C++引入运算符重载,极大的增强了代码的可读性。

前加加、后加加

class Int
{
public:
	Int(int i = 0)
	{
		m_i = i;
	}
	//前加加
	Int& operator++()
	{
		m_i++;
		return *this;
	}
	//后加加
	Int operator++(int)
	{
		Int tmp = *this;
		m_i++;
		return tmp;
	}
private:
	int m_i;
};

前加加的返回类型就是自身类型的引用,后加加返回类型就是本类型,这个要注意,另外,在后加加我们加了一个int类型参数,没有实际意义,只是为了区分前加加和后加加。
前减减和后减减的重载方法和前加加后加加类似。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值