C++模板 类模板案例 通用的数组类

类模板案例-实现一个通用的数组类

1. 要求

1.可以对内置数据类型以及自定义数据类型的数据进行存储
2.将数组中的数据存储到堆区
3.构造函数中可以传入数组的容量
4.提供对应的拷贝构造函数以及operator=防止浅拷贝问题
5.提供尾插法和尾删法对数组中的数据进行增加和删除
6.可以通过下标的方式访问数组中的元素
7.可以获取数组中当前元素个数和数组的容量

2. 需求分析

在这里插入图片描述

3. 数组类模板要求1-4的步骤及注意点:

  1. 分文见编写.hpp文件:把类模板分文见编写,类模板的声明和实现写在一起;
  2. 类模板MyArray: 包括私有成员属性和对外提供接口的公共成员函数,其中成员函数包括有参构造函数、析构函数、拷贝构造、operator=;
  3. 有参构造函数MyArray(): 私有属性,数组的容量capacity,数组的大小siza,开辟在堆区的数组pAddress,其中数组类型及其数据都是通用数据类型T,即模板化。根据传入的数组容量来在堆区开辟该容量的数组,数组大小初始值为0;
  4. 析构函数~MyArray(): 有参构造函数中在堆区开辟了数据,手动开辟需要手动释放,因此需要在此判断堆区数组是否释放干净。如果没有,再次释放;
  5. 拷贝构造: 数组容量和大小都可以浅拷贝,但是数组是堆区的数据,浅拷贝会引发析构的重复释放。采用深拷贝解决,在堆区再次开辟一个数组,并将原数组的所有数据都拷贝到新数组中;
  6. operator=: 也是为了防止浅拷贝的问题,与拷贝构造不同的是,首先要判断在堆区的原数组释放释放干净,如果没有需要再次释放。然后,再在堆区开辟新数组,并拷贝原数组的所有数据。
  7. 测试以上六点是否成功实现

4. 数组类模板要求1-4的代码与测试:

.hpp文件

#pragma once
#include <iostream>
using namespace std;

//自己的通用数组类声明

template<class T>
class MyArray
{
public:
	//有参构造 参数:容量
	MyArray(int capacity)
	{
		cout << "MyArray 有参构造 调用" << endl;//测试代码
		this->m_Capacity = capacity;//根据传入的数组容量来初始化
		this->m_Size = 0;//初始数组大小为0
		this->pAddress = new T[this->m_Capacity];//根据容量在堆区开辟T类型的数组,每一个数据都是T类型
	}

	//拷贝构造 浅拷贝 深拷贝
	MyArray(const MyArray& arr)
	{
		cout << "MyArray 拷贝构造 调用" << endl;//测试代码
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		this->pAddress = arr.pAddress;//引发浅拷贝,重复释放同一块内存,

		//深拷贝解决浅拷贝问题
		this->pAddress = new T[arr.m_Capacity];

		//将arr所有数据都拷贝
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
	}

	//operator= 防止浅拷贝
	MyArray& operator=(const MyArray& arr)
	{
		cout << "MyArray operator= 调用" << endl;//测试代码
		//先判断原来堆区是否有数据,如果有,先释放
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
			this->m_Size = 0;
			this->m_Capacity = 0;
		}

		//深拷贝
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		this->pAddress = new T[arr.m_Capacity];

		//拷贝arr所有数据
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
		return *this;
	}


	//析构函数 堆区数据手动开辟手动释放
	~MyArray()
	{
		cout << "MyArray 析构函数 调用" << endl;//测试代码
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
		}
	}
private:
	T* pAddress;//指针指向堆区开辟的真实数组
	int m_Capacity;//数组容量
	int m_Size;//数组大小
};

测试文件

#include <iostream>
using namespace std;
#include "MyArray.hpp"

void test()
{
	cout << "arr1" << endl;
	MyArray<int> arr1(5);//指定MyArray中的T是int类型
	cout << string(30, '-') << endl;
	cout << "arr2" << endl;
	MyArray<int> arr2(arr1);//测试拷贝构造 深浅拷贝
	cout << string(30, '-') << endl;
	cout << "arr3" << endl;
	MyArray<int> arr3(10);
	arr3 = arr1;//测试operator=
	cout << string(30, '-') << endl;
}

int main()
{
	test();
	cout << endl;
	system("pause");
	return 0;
}

在这里插入图片描述

  • 创建arr1时,使用有参构造;
  • 创建arr2则是使用拷贝构造;
  • 创建arr3首先使用有参构造,再把arr1通过赋值=拷贝给arr3

5. 数组类模板要求5-7的步骤及注意点:

  1. 尾插法:首先判断数组是否满了,如果没有满,再插入新数据。函数的形参通过引用的方式值为val类型为T的常量,还要注意数组的大小要更新;
  2. 尾删法: 首先判断数组是否空,不为空再做逻辑删除,也就是让数组访问不到最后一个数据;
  3. 通过下标方式访问数组元素: 需要明确几点,如下
  • 通常访问一个数组arr,只需要通过一个 整型下标[] 访问,但这只能访问内置的数据类型。对于自定的数据类型的数组MyArray, [] 是无法访问的,所以需要重载 []
  • 通过下标访问数组,这个下标只能是整数,因此形参类型是int
  • [] 访问数组时,应该返回该数组的数据,而数据的类型是T,因此重载函数的返回值类型也是T
  • [] 访问数组时,如果想做赋值操作,MyArray[index] = 100,也就是这个函数做为左值存在,因此需要返回数据本身,因此返回值需要使用引用的方式,T&
  1. 返回数组的容量: 返回自身属性capacity即可;
  2. 返回数组的大小: 返回自身属性size即可;
  3. 测试以上五点是否成功实现

6. 数组类模板要求5-7的代码:

.hpp文件加入

//尾插法
void Push_Back(const T& val)//引用的方式传入值为val类型为T的常量
{
	//首先判断数组是否满了
	if (this->m_Capacity == this->m_Size)
	{
		cout << "数组已满,无法插入新数据!" << endl;
		return;
	}
	this->pAddress[this->m_Size] = val;//在尾部插入新数据
	this->m_Size++;//数组大小要更新
}

//尾删法
void Pop_Back()
{
	//判断数组是否为空数组
	if (this->m_Size == 0)
	{
		cout << "数组为空,无法删除!" << endl;
		return;
	}
	//delete this->pAddress[this->m_Size];
	this->m_Size--;//逻辑删除,访问不到最后一个数据
}

//通过下标方式访问数组元素
T& operator[](int index)
{
	return this->pAddress[index];
}

//返回数组的容量
int getCapacity()
{
	return this->m_Capacity;//返回自身属性
}

//返回数组的大小
int getSize()
{
	return this->m_Size;//返回自身属性
}

7. 数组类模板要求5-7-内置数据类型测试:

测试文件

//打印数组 内置数据类型
void printIntArr(MyArray<int>& arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << arr[i] << '\t';//operator[]
	}
	cout << endl;
}

//数组类5-7 内置数据类型测试
void test2()
{
	int s = 60;
	cout << "内置数据类型测试 int" << endl;
	cout << string(s, '-') << endl;
	cout << "arr1" << endl;
	MyArray<int> arr1(5);
	for(int i = 0; i < 5; i++)//获取数组大小
	{
		arr1.Push_Back(i+1);//尾插法
	}
	cout << "arr1 打印:\t";
	printIntArr(arr1);
	cout << "arr1 数组容量:" << arr1.getCapacity() << endl;//获取数组容量
	cout << "arr1 数组大小:" << arr1.getSize() << endl;
	cout << string(s, '-') << endl;

	cout << "arr2" << endl;
	MyArray<int> arr2(arr1);//拷贝构造
	cout << "arr2 尾删前打印:\t";
	printIntArr(arr2);
	cout << "arr2 尾删前数组容量:" << arr2.getCapacity() << endl;//获取数组容量
	cout << "arr2 尾删前数组大小:" << arr2.getSize() << endl;
	cout << string(s, '-') << endl;
	arr2.Pop_Back();
	cout << "arr2 尾删后打印:\t";
	printIntArr(arr2);
	cout << "arr2 尾删后数组容量:" << arr2.getCapacity() << endl;//获取数组容量
	cout << "arr2 尾删后数组大小:" << arr2.getSize() << endl;
	cout << string(s, '-') << endl;

	cout << "自定义数据类型测试 Person" << endl;
	cout << "arr3" << endl;
	MyArray<int> arr3(10);
	cout << string(s, '-') << endl;
}

在这里插入图片描述

8. 数组类模板要求5-7-自定义数据类型测试:

测试文件

class Person
{
public:
	Person() {};//默认构造 空实现
	Person(string name, int age):m_name(name), m_age(age) 	{	}


	string m_name;
	int m_age;
};

//打印数组 自定义数据类型
void printPersonArr(MyArray<Person>& arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << "姓名:" << arr[i].m_name << '\t'
			 << "年龄:" << arr[i].m_age << endl;//operator[]
	}
}

//数组类5-7 自定义数据类型测试
void test3()
{
	int s = 40;
	cout << "自定义数据类型测试 Person" << endl;
	cout << string(s, '-') << endl;
	cout << "arr1" << endl;
	MyArray<Person> arr1(10);
	Person p1("刘备", 23);
	Person p2("关羽", 22);
	Person p3("张飞", 29);
	Person p4("貂蝉", 24);
	Person p5("西施", 25);
	arr1.Push_Back(p5);
	arr1.Push_Back(p2);
	arr1.Push_Back(p3);
	arr1.Push_Back(p4);
	arr1.Push_Back(p1);

	cout << "arr1 打印" << endl;
	printPersonArr(arr1);
	cout << "arr1 数组容量:" << arr1.getCapacity() << endl;//获取数组容量
	cout << "arr1 数组大小:" << arr1.getSize() << endl;
	cout << string(s, '-') << endl;

	cout << "arr2" << endl;
	MyArray<Person> arr2(arr1);//拷贝构造
	cout << "arr2 尾删前打印:" << endl;
	printPersonArr(arr2);
	cout << "arr2 尾删前数组容量:" << arr2.getCapacity() << endl;//获取数组容量
	cout << "arr2 尾删前数组大小:" << arr2.getSize() << endl;
	cout << string(s, '-') << endl;
	arr2.Pop_Back();
	cout << "arr2 尾删后打印:" << endl;
	printPersonArr(arr2);
	cout << "arr2 尾删后数组容量:" << arr2.getCapacity() << endl;//获取数组容量
	cout << "arr2 尾删后数组大小:" << arr2.getSize() << endl;
	cout << string(s, '-') << endl;
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值