178-类和对象代码应用实践-针对拷贝构造和赋值重载(String类型和循环队列Queue)

1、实现String类型

在这里插入图片描述
这个类的对象的成员变量有占用外部资源,所以我们要重写它的拷贝构造函数和赋值函数。

为了支持连续赋值,需要返回引用类型!
在这里插入图片描述
str2给str1赋值后,要返回str1对象本身,才能给str3赋值。
在这里插入图片描述

#include <iostream>
using namespace std;



class String
{
public:
	String(const char* str = nullptr)//普通构造函数
	{
		if (str != nullptr)
		{
			m_data = new char[strlen(str) + 1];//'\0'要算上 
			strcpy(this->m_data, str);
		}
		else//用户传进来的字符串是空的话 ,为了让其他方法不用判空 
		{
			m_data = new char[1];//new char;开辟1个字节大小的空间 
			*m_data = '\0';//0
		}
	}
	String(const String& other)//拷贝构造函数,深拷贝 
	{
		m_data = new char[strlen(other.m_data) + 1];
		strcpy(m_data, other.m_data);
	}
	~String(void)//析构函数
	{
		delete[]m_data;
		m_data = nullptr;//防止野指针的出现 
	}
	//使用String&是为了支持连续的operator=赋值操作
	String& operator=(const String& other)//赋值重载函数,深拷贝 
	{
		if (this == &other)//防止自赋值 
		{
			return *this;//str1
		}

		delete[]m_data;//释放当前的外部资源 

		m_data = new char[strlen(other.m_data) + 1];
		strcpy(m_data, other.m_data);
		return *this;//str1
	}

private:
	char* m_data;//用于保存字符串
};
int main()
{
	//用带const char*参数的构造函数
	String str1;//调用默认的构造,形参是nullptr 
	String str2("hello");
	String str3 = "world";//str2 

	//调用拷贝构造函数
	String str4 = str3;
	String str5(str3);

	//调用赋值重载函数
	/*
	str1 = str2
	str1.operator=(str2) => str1
	str3 = str1
	*/
	str3 = str1 = str2;

	return 0;
}

2、实现循环队列queue

初始化的时候,两个指针都指向队头:
在这里插入图片描述
随着元素的添加,rear指针后移:
在这里插入图片描述
如果到了下面这种情况,添加元素满了:
在这里插入图片描述
然后现在有元素出队,从队头出,front指针也要后移:
在这里插入图片描述

  • 如果是用顺序表实现队列,那么现在,不能入队了,因为已经满了,前面有元素出队,但是没办法放。
  • rear++的时候,我们不要让他加到末尾,让他加到前面去;
  • 包括front也一样,把78出队后,回到队前面。

在这里插入图片描述
因为成员变量中有指针指向堆内存,因此需要防止浅拷贝:

  • 1、直接在C++11中将拷贝构造和赋值重载delete;
    在这里插入图片描述
    在这里插入图片描述
    这样我们就直接不能使用了!

  • 2、自定义拷贝构造和赋值重载 函数;
    在这里插入图片描述

#include <iostream>
using namespace std;


//循环队列  memcpy  realloc
class Queue
{
public:
	Queue(int size = 5)//构造函数 
	{
		_pQue = new int[size];
		_front = _rear = 0;
		_size = size;
	}
	//Queue(const Queue&) = delete;
	//Queue& operator=(const Queue&) = delete;

	Queue(const Queue& src)//拷贝构造函数 
	{
		_size = src._size;
		_front = src._front;
		_rear = src._rear;
		_pQue = new int[_size];
		for (int i = _front;
			i != _rear;
			i = (i + 1) % _size)
		{
			_pQue[i] = src._pQue[i];
		}
	}
	Queue& operator=(const Queue& src)//赋值函数 
	{
		//防止自赋值
		if (this == &src)
			return *this;

		delete[]_pQue;

		_size = src._size;
		_front = src._front;
		_rear = src._rear;
		_pQue = new int[_size];
		for (int i = _front;
			i != _rear;
			i = (i + 1) % _size)
		{
			_pQue[i] = src._pQue[i];
		}
		return *this;
	}

	//析构函数 
	~Queue()
	{
		delete[]_pQue;
		_pQue = nullptr;
	}

	//入队操作,队尾入 
	void push(int val)
	{
		if (full())
			resize();
		_pQue[_rear] = val;//队尾赋值 
		_rear = (_rear + 1) % _size;//因为是循环队列 
	}

	//出队操作
	void pop()
	{
		if (empty())
			return;
		_front = (_front + 1) % _size;
	}

	//获取队头元素
	int front()
	{
		return _pQue[_front];
	}

	bool full() { return (_rear + 1) % _size == _front; }//判满 
	bool empty() { return _front == _rear; }//判空 

private:

	void resize()//扩容操作 
	{
		int* ptmp = new int[2 * _size];
		int index = 0;
		for (int i = _front; i != _rear; i = (i + 1) % _size)
		{
			ptmp[index++] = _pQue[i];
		}
		delete[]_pQue;
		_pQue = ptmp;
		_front = 0;
		_rear = index;
		_size *= 2;
	}

	int* _pQue;//申请队列的数组空间,方便扩容 
	int _front;//指示队头的位置
	int _rear;//指示队尾的位置
	int _size;//队列扩容的总大小
};



int main()
{
	Queue queue;
	for (int i = 0; i < 20; ++i)
	{
		queue.push(rand() % 100);
	}

	while (!queue.empty())
	{
		cout << queue.front() << " ";
		queue.pop();
	}
	cout << endl;

	Queue queue1 = queue;
	queue1 = queue;

	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liufeng2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值