C++ 类模板案例–数组封装
最近这段时间,抽时间一直在看c++的视频和书籍。今天正好把类模板的这部分给学完了,正好总结总结,分析一个视频里的案例吧。废话不多说,直接开始。
程序要求如下:
1、可以对内置数据类型以及自定义数据类型的数据进行存储。
2、将数组中的数据存储到堆区。
3、构造函数中可以传入数组的容量
4、提供对应的拷贝构造函数以及operator=防止浅拷贝问题。
5、提供尾插法和尾删法对数组中的数据进行增加和删除。
6、可以通过下标的方式访问数组中的元素。
7、可以获取数组中当前元素个数和数组容量。
一、总体对程序设计进行分析
二、程序实现
1、先将程序分文件编写
添加头文件以写声明
因为是类模板成员函数分文件编写,类模板中成员函数创建时机在调用阶段,导致分文件编写时链接不到,所以在这里为解决这个问题,将声明和实现写到同一文件中,并更改后缀名为**.hpp**(hpp是约定名称,并不是强制)
2、在MyArray中写自己通用的数组类
(1)先写标准的程序引入
//自己通用的数组类
#pragma once//防止头文件重复包含
#include<iostream>//标准的io流,头文件引入
using namespace std;//使用标准命名空间
(2)写一下MyArray这个类中需要维护的几个私有属性
template<class T>//因为T不识别,故加类模板T
class MyArray
{
private:
T*pAddress;//指针指向堆区开辟的真实数组
int m_Capacity;//数组容量
int m_Size;//数组大小
}
(3)接下来需要写对外的一些成员函数
public:
//有参构造,写参数和容量
MyArray(int capacity)
{
this->m_Capacity=capacity;//通过参数传入容量
this->m_Size=0;//初始化赋值为0
this->pAddress=new T[this->m_Capacity];//在堆区创建数据
}
//防止浅拷贝提供拷贝构造函数
MyArray(const MyArray& arr)
{
//编译器提供
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)
{
//先判断原来堆区是否有数据,如果有先释放
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;//最后需要将参数返回
}
//因为堆区创建数据,是手动开辟,手动释放故需要写一个析构函数
//析构函数
~MyArray()
{
if(this->pAddress!=NULL)
{
delete[]this->pAddress;
}
}
(4)通过尾插法和尾删法对数组中的数据进行增加和删除
(代码如下:)
//尾插法
void Push_Back(const T & vai)
{
//判断容量是否等于大小,若满了的话无法插入,直接返回
if(this->m_Capacity==this->m_Size)
{
return;
}
this->pAddress[this->m_Size]=vai;//在数组末尾插入数据
this->m_Size++;//更新数组大小
}
//尾删法
void Pop_Back()
{
//让用户访问不到最后一个元素,即为尾删,逻辑删除
if(this->m_Size==0)
{
return;
}
this->m_Size--;
}
(5)通过下标方式访问数组中的元素
T& operator[](int index)
{
return this->pAddress[index];
}
(6)返回数组容量与数组大小
//返回数组容量
int getCapacity()
{
return this->m_Capacity;
}
//返回数组大小
int getSize()
{
return this->m_Size;
}
(7)写测试打印函数,并打印arr1的容量与大小
//写一个打印函数
void printIntArray(MyArray<int>& arr)
{
for(int i=0;i<arr.getSize();i++)
{
cout<<arr[i]<<endl;
}
}
//写一个测试函数利用尾插法来测试
void test01()
{
MyArray<int>arr1(5);
for(int i=0;i<5;i++)
{
arr1.Push_Back(i);
}
cout<<"arr的打印输出为:"<<endl;
printIntArray(arr1);
//测试一下arr的容量以及大小
cout<<"arr1的容量为:"<<arr1.getCapacity()<<endl;
cout<<"arr1的大小为:"<<arr1.getSize()<<endl;
}
(8)利用arr2测尾删法
MyArray<int>arr2(arr1);
cout<<"arr2的打印输出为:"<<endl;
printIntArray(arr2);
//尾删
arr2.Pop_Back();
cout<<"arr2的容量为:"<<arr2.getCapacity()<<endl;
cout<<"arr2的大小为:"<<arr2.getSize()<<endl;
}
(9)测试结果如下图
(10)最后为自定义数据类型的测试
测试函数如下:
//测试自定义数据类型
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<<"年龄"<<arr[i].m_Age<<endl;
}
}
void test02()
{
MyArray<Person>arr(10);
Person p1("wjx",20);
Person p2("p",20);
Person p3("hh",908);
Person p4("aa",308);
Person p5("999",999);
//将数据插入到数组中
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;
}
测试结果如图所示:
以上就是我总结的有关类模板的案例,这个案例觉得非常不错,里面的参数重载,深拷贝浅拷贝等都非常值得学习一下,先总的写一下类模板的案列,接下来有时间把这两星期记得类模板的其他基本知识给写一写,加油!