C++——类模板经典案例——自定义通用数组类

案例:自定义数组类
需求:
1,对内置数据及自定义数据类型的数据存储
2,将数组中的数据存储到堆区
3,构造函数中可以存入数组的容量
4,提供对应的拷贝构造函数和=运算符重载防止浅拷贝问题的发生
5,提供尾插法和尾删法对数组中的数据进行增加和删除
6,提供下标的方式访问数组中的元素
7,获取数组中当前元素个数和数组的容量

代码的注释写的很详细了,个人觉得没啥好解释的,认真看看,都能看懂,很经典的案例,值得学习!!!

一、yy_Array.hpp

yy_Array.hpp文件包括:自定义数组类以及类的成员函数、构造函数、析构函数等相应实现

//防止头文件重复包含
#pragma once

#include<iostream>
template<class T>
class yy_Array 
{
public:
	yy_Array(int capacity)//有参构造函数,传入数组初始的容量
	{
		std::cout << "有参构造" << std::endl;
		this->capacity_ = capacity;
		this->size_ = 0; //数组刚开始一个元素都没有
		this->p_address_ = new T[this->capacity_];//开辟一块堆区空间,大小为数组的容量
	}

	//拷贝构造(为例防止堆区带来的浅拷贝问题)
	//若属性有在堆区开辟的,一定要用自己的拷贝构造函数,防止系统默认使用浅拷贝带来的问题
	//这里需要在堆区开辟数组,故有在堆区开辟的属性,需要使用自己的拷贝构造函数
	yy_Array(const yy_Array& arr) 
	{
		std::cout << "拷贝构造" << std::endl;
		this->capacity_ = arr.capacity_;
		this->size_ = arr.size_;
		this->p_address_ = new T[arr.capacity_]; //因为是堆内存,要重新开辟空间,深拷贝

		//若数组中本身就有数据,在深拷贝时,也需要拷贝过来
		for (int i = 0; i < this->size_; i++) 
		{
			this->p_address_[i] = arr.p_address_[i];
		}
	}


	//赋值运算符重载operator=,也是为了防止浅拷贝问题
	yy_Array& operator=(const yy_Array& arr) //返回本身,因为实际系统的赋值运算符支持a=b=c
	{
		std::cout << "运算符重载operator=" << std::endl;
		//先判断原来堆区中是否有数据,若事前有数据,先释放掉
		if (this->p_address_ != NULL) 
		{
			delete[] this->p_address_;//释放这个指向数组的指针
			this->p_address_ = NULL;//指针置空,防止野指针
			this->capacity_ = 0;
			this->size_ = 0;
		}

		//深拷贝,从堆区开辟内存
		this->capacity_ = arr.capacity_;
		this->size_ = arr.size_;
		this->p_address_ = new T[arr.capacity_]; //因为是堆内存,要重新开辟空间,深拷贝

		//若数组中本身就有数据,在深拷贝时,也需要拷贝过来
		for (int i = 0; i < this->size_; i++)
		{
			this->p_address_[i] = arr.p_address_[i];
		}

		return *this;//返回自身
	}

	//尾插法
	void Push_Back(const T& val) 
	{
		//若容量已经满了,进行提示
		if (this->capacity_ == this->size_) 
		{
			std::cout << "数组已满" << std::endl;
			return;
		}
		else 
		{
			this->p_address_[this->size_] = val;//传入的val插到数组最后一个
			this->size_++;//插入一个元素,数组大小要进行更新
		}
	}


	//尾删法
	void Pop_Back()//删除操作不需要传参,直接把最后一个元素干掉即可,也就是让用户访问不到即可
	{
		//要进行尾删法,首先数据中必须有元素
		if (this->size_ == 0) 
		{
			std::cout << "数组已为空" << std::endl;
			return;
		}
		else 
		{
			this->size_--;//用户访问不到最后一个元素即可
		}
	}


	//通过下标的方式进行访问数组中的元素
	//因为是自己写的模板数组,单纯的a[0]是无法进行访问的,故需要重新对[]运算符进行重载
	T& operator[](int index) 
	{
		return this->p_address_[index];
	}

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

	//返回数据的大小
	int getSize() 
	{
		return this->size_;
	}


	~yy_Array()//析构函数
	{
		if (p_address_ != NULL) 
		{
			std::cout << "析构函数" << std::endl;
			delete[] this->p_address_;//释放这个指向数组的指针
			this->p_address_ = NULL;//指针置空,防止野指针
		}
	}


private:
	T* p_address_; //指针指向堆区开辟的真实数组
	int capacity_;//数组的容量,即数组最多存放多少元素
	int size_;//数组当前有多少个元素
};

二、array.cpp

主函数入口,分成三个函数(test1()、test2()以及test3())进行不同功能的测试
调试学习时,将主函数中test1()test2()test3()挨个取消注释,运行单个测试函数进行学习

#include <iostream>
#include "yy_Array.hpp"

void printIntArr(yy_Array<int>& arr) //打印输出数组内的元素
{
	for (int i = 0; i < arr.getSize(); i++) 
	{
		std::cout << arr[i] << std::endl;
	}
}

void test1() 
{
	yy_Array<int>yy_arr_1(5);//测试 有参构造函数 和 析构函数

	yy_Array<int>yy_arr_2(yy_arr_1);//测试 拷贝构造函数 和 析构函数

	yy_Array<int> yy_arr_3(100);//测试 有参构造 和 析构函数
	yy_arr_3 = yy_arr_1;//测试 运算符重载operator= 和 析构函数
}

void test2() 
{
	yy_Array<int>yy_arr_1(10);//测试 有参构造函数 和 析构函数
	//测试尾插法,利用尾插法向数组中插入数据
	for (int i = 0; i < 10; i++) 
	{
		yy_arr_1.Push_Back(i);
	}
	std::cout << "yy_arr_1的元素为:" << std::endl;
	printIntArr(yy_arr_1);
	//测试数组容量
	std::cout << "yy_arr_1的容量为:" << yy_arr_1.getCapacity() << std::endl;
	//测试数组大小
	std::cout << "yy_arr_1的目前大小为:" << yy_arr_1.getSize() << std::endl;


	yy_Array<int>yy_arr_2(yy_arr_1);//测试 拷贝构造函数 和 析构函数
	std::cout << "yy_arr_2的元素为:" << std::endl;
	printIntArr(yy_arr_2);
	//测试数组容量
	std::cout << "yy_arr_2的容量为:" << yy_arr_2.getCapacity() << std::endl;
	//测试数组大小
	std::cout << "yy_arr_2的目前大小为:" << yy_arr_2.getSize() << std::endl;
	
	//测试尾删法
	yy_arr_2.Pop_Back();
	//测试数组容量
	std::cout << "yy_arr_2尾删后的容量为:" << yy_arr_2.getCapacity() << std::endl;
	//测试数组大小
	std::cout << "yy_arr_2尾删后的目前大小为:" << yy_arr_2.getSize() << std::endl;
}




//测试自定义数据类型
class Beyond 
{
public:
	Beyond() {};//无参构造函数
	Beyond(std::string name, int age)
	{
		this->name_ = name;
		this->age_ = age;
	}
	std::string name_;
	int age_;
};
//输出自定义数据类型
void printBeyondArr(yy_Array<Beyond>& arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		std::cout << "姓名:" << arr[i].name_ << "年龄:" << arr[i].age_ << std::endl;
	}
}
void test3() 
{
	yy_Array<Beyond> arr(5);
	Beyond hjj("黄家驹", 31);
	Beyond hjq("黄家强", 56);
	Beyond hgz("黄贯中", 57);
	Beyond ysr("叶世荣", 58);

	//将数据通过尾插法插入到数组中
	arr.Push_Back(hjj);
	arr.Push_Back(hjq);
	arr.Push_Back(hgz);
	arr.Push_Back(ysr);

	//输出数组数据
	printBeyondArr(arr);

	//测试数组容量
	std::cout << "arr的容量为:" << arr.getCapacity() << std::endl;
	//测试数组大小
	std::cout << "arr的目前大小为:" << arr.getSize() << std::endl;
}


int main(int argc, char* argv[])
{
	test1();
	test2();
	test3();
	return 0;
}

三、测试结果

在这里插入图片描述

  • 12
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

beyond谚语

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

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

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

打赏作者

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

抵扣说明:

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

余额充值