C++中类模版案例——数组封装(附C++代码)

在这里插入图片描述

💪 图像算法工程师,专业从事且热爱图像处理,图像处理专栏更新如下👇:
📝《图像去噪》
📝《超分辨率重建》
📝《语义分割》
📝《风格迁移》
📝《目标检测》
📝《图像增强》
📝《模型优化》
📝《模型实战部署》
📝《图像配准融合》
📝《数据集》
📝《高效助手》
📝《C++》


在这里插入图片描述

一、要求

实现一个通用的数组类,要求如下:

  • 可以对内置数据类型以及自定义数据类型的数据进行存储;

  • 将数组中的数据存储到堆区;

  • 构造函数中可以传入数组的容量;

  • 提供对应的拷贝构造函数以及operator=防止浅拷贝问题;

  • 提供尾插法和尾删法对数组中的数据进行增加和删除;

  • 可以通过下标的方式访问数组中的元素;

  • 可以获取数组中当前元素个数和数组的容量;

二、实现

2.1 类模版的创建

创建一个MyArray.hpp文件和一个主函数main.cpp文件,见下:
在这里插入图片描述

类模版定义代码见下,写在MyArray.hpp文件中:

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

template<class T>
class MyArray
{

private:
	T* pAddress;       // 指针指向堆区开辟的真实数据
	int m_Capacity;    // 数组容量
	int m_Size;        // 数组大小
};

2.2 构造函数

有参构造函数的定义见下,包含数组的容量、大小和地址,做初始化操作,代码见下:

// 有参构造 参数容量
	MyArray(int capacity)
	{
		cout << "Myarray有参构造调用" << endl;
		this->m_Capacity = capacity;
		this->m_Size = 0;
		this->pAddress = new T[this->m_Capacity];
	}

2.3 拷贝构造函数

拷贝构造函数代码见下:

// 拷贝构造
	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];
		}
	}

2.4 深拷贝

对 = 操作符进行重载,防止浅拷贝问题,关于深拷贝和浅拷贝的理解,参考我另外一篇博文:C++中的深拷贝和浅拷贝通俗故事理解

深拷贝代码见下:

// 重载 = 操作符 防止浅拷贝问题
	MyArray& operator = (const MyArray& arr)
	{
		cout << "Myarray 的 operator=构造调用" << endl;
		// 先判断原来堆区是否有数据,如果有先释放
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
			this->m_Capacity = 0;
			this->m_Size = 0;
		}

		// 深拷贝
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		this->pAddress = new T[arr.m_Capacity];
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
		return *this;
	}

2.5 重载[ ]操作符

重载[ ]操作符是为了后面能够通过arr[i]访问数组中的元素,代码见下:

// 重载 [] 操作符 ,通过下标方式访问数组中的元素 arr[0]=100
	T& operator[](int index)  // 运算符重载
	{
		return this->pAddress[index];
	}

2.6 尾插法

在数组尾端插入元素的代码见下:

// 尾插法
	void Push_Back(const T& val)
	{
		// 判断容量是否等于大小
		if (this->m_Capacity == this->m_Size)
		{
			return;
		}
		this->pAddress[this->m_Size] = val;    // 在数组的尾端插入数据
		this->m_Size++;                        // 更新数组大小
	}

2.7 尾删法

在数组尾端删除元素的代码见下:

// 尾删法
	void Pop_Back()
	{
		// 让用户访问不到最后一个元素,即为尾删,逻辑删除
		if (this->m_Size == 0)
		{
			return;
		}
		this->m_Size--;
	}

2.8 获取数组容量

获取数组容量代码见下:

// 返回数组容量
	int getCapacity()
	{
		return this->m_Capacity;
	}

2.9 获取数组长度

获取数组长度代码见下:

// 返回数组大小
	int getSize()
	{
		return this->m_Size;
	}

2.10 析构函数

在析构函数中,主要写在堆区创建内存数据释放,并将指针置为空,避免野指针,将数组容量和大小都置为0,代码见下:

// 析构函数
	~MyArray()
	{
		if (this->pAddress != NULL)
		{
			cout << "Myarray析构函数的调用!" << endl;
			delete[] this->pAddress;    // 将堆区中的数据释放
			this->pAddress = NULL;
			this->m_Capacity = 0;
			this->m_Size = 0;
		}
	}

2.11 完整代码

上面各个模块组合起来的完整代码见下,写在MyArray.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;
		this->pAddress = new T[this->m_Capacity];
	}
	
	// 拷贝构造,为了防止浅拷贝的问题
	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++)
		{
			// 如果T为对象,而且还包含指针,必须需要重载=操作符,因为这个等号不是构造而是赋值。
			// 普通类型可以直接=,但是指针类型需要深拷贝
			this->pAddress[i] = arr.pAddress[i];
		}
	}

	// 重载 = 操作符 防止浅拷贝问题
	MyArray& operator = (const MyArray& arr)
	{
		cout << "Myarray 的 operator=构造调用" << endl;
		// 先判断原来堆区是否有数据,如果有先释放
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
			this->m_Capacity = 0;
			this->m_Size = 0;
		}

		// 深拷贝
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		this->pAddress = new T[arr.m_Capacity];
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
		return *this;
	}

	// 重载 [] 操作符 ,通过下标方式访问数组中的元素 arr[0]=100
	T& operator[](int index)  // 运算符重载
	{
		return this->pAddress[index];
	}

	// 尾插法
	void Push_Back(const T& val)
	{
		// 判断容量是否等于大小
		if (this->m_Capacity == this->m_Size)
		{
			return;
		}
		this->pAddress[this->m_Size] = val;    // 在数组的尾端插入数据
		this->m_Size++;                        // 更新数组大小
	}


	// 尾删法
	void Pop_Back()
	{
		// 让用户访问不到最后一个元素,即为尾删,逻辑删除
		if (this->m_Size == 0)
		{
			return;
		}
		this->m_Size--;
	}


	// 返回数组容量
	int getCapacity()
	{
		return this->m_Capacity;
	}

	// 返回数组大小
	int getSize()
	{
		return this->m_Size;
	}

	// 析构函数
	~MyArray()
	{
		if (this->pAddress != NULL)
		{
			cout << "Myarray析构函数的调用!" << endl;
			delete[] this->pAddress;    // 将堆区中的数据释放
			this->pAddress = NULL;
			this->m_Capacity = 0;
			this->m_Size = 0;
		}
	}

private:
	T* pAddress;       // 指针指向堆区开辟的真实数据
	int m_Capacity;    // 数组容量
	int m_Size;        // 数组大小
};

三、测试

3.1 内置数据类型测试

3.1.1 代码

内置数据类型测试代码见下,写在Array_class_encapsulation_main.cpp文件中:

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

// 打印数组中的元素
void printIntArray(MyArray<int>& arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << arr[i] << endl;
	}
}

void test01()
{
	MyArray<int>arr1(5);

	//MyArray<int>arr2(arr1);

	//MyArray<int>arr3(100);   // 本来有100个数据,100的容量
	//arr3 = arr1;      // 做等号赋值的时候先把100清空,再把arr1中的数据做深拷贝操作

	for (int i = 0; i < 5; i++)
	{
		// 利用尾插法向数组中插入数据
		arr1.Push_Back(i);
	}
	cout << "arr1的打印输出为:" << endl;
	printIntArray(arr1);

	cout << "arr1的容量为:" << arr1.getCapacity() << endl;
	cout << "arr1的大小为:" << arr1.getSize() << endl; 

	MyArray<int>arr2(arr1);
	cout << "arr2的打印输出为:" << endl;
	printIntArray(arr2);

	// 尾删
	arr2.Pop_Back();
	cout << "arr2的容量为:" << arr2.getCapacity() << endl;
	cout << "arr2的大小为:" << arr2.getSize() << endl;
}

int main()
{
	test01();
	//test02();

	system("pause");
	return 0;
}

3.1.2 输出

运行3.1.1中代码,输出见下:

在这里插入图片描述

3.2 自定义数据类型测试

3.2.1 代码

自定义数据类型测试代码见下,写在Array_class_encapsulation_main.cpp文件中:

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

// 测试自定义数据集
class Person
{
public:
	Person() {};    // 默认构造
	Person(string name, int age)    // 有参构造
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	string m_Name;
	int m_Age;
};

void printPersonArray(MyArray<Person>& arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << "姓名:" << arr[i].m_Name <<"\t" << "年龄:" << arr[i].m_Age << endl;
	}
}

void test02()
{
	MyArray<Person> arr(10);

	Person p1("李元芳", 18);
	Person p2("公孙离", 20);
	Person p3("虞姬", 28);
	Person p4("狄仁杰", 40);
	Person p5("孙尚香", 30);

	// 将数据插入到数组中
	arr.Push_Back(p1);
	arr.Push_Back(p2);
	arr.Push_Back(p3);
	arr.Push_Back(p4);
	arr.Push_Back(p5);

	// 打印数组
	printPersonArray(arr);

	// 输出容量
	cout << "arr的容量为:" << arr.getCapacity() << endl;
	// 输出大小
	cout << "arr的大小为:" << arr.getSize() << endl;
}

int main()
{
	//test01();
	test02();

	system("pause");
	return 0;
}

3.2.2 输出

运行3.2.1中代码,输出见下:

在这里插入图片描述

四、总结

以上就是C++中类模版案例,数组封装,希望能帮你理解。本人参考学习的是黑马程序员,仅作为笔记记录。

感谢您阅读到最后!😊总结不易,多多支持呀🌹 点赞👍收藏⭐评论✍️,您的三连是我持续更新的动力💖

关注下面「视觉研坊」,获取干货教程、实战案例、技术解答、行业资讯!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

视觉研坊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值