类模板案例:实现一个通用的数组类
3.9 类模板案例
案例描述:
实现一个通用的数组类
要求如下:
(1)、可以对内置数据类型以及自定义数据类型的数据进行存储;
(2)、将数组中的数据存储到堆区;
(3)、构造函数中可以传入数组的容量;
(4)、提供对应的拷贝构造函数以及operator=防止浅拷贝问题;
(5)、提供尾插法和尾删法对数组中的数据进行增加和删除;
(6)、可以通过下标的方式访问数组中的元素;
(7)、可以获取数组中当前元素个数和数组的容量。
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;
pAddress = new T[this->m_Capacity]; // 堆区数据,按照容量m_Capacity开辟堆区数组空间;在堆区创建一个对象pAddress
}
// 拷贝构造
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[this->m_Capacity];
// 将arr中的数据都拷贝过来
for (int i = 0; i < this->m_Size; i++)
{
// 如果T为对象,而且还包含指针,必须需要重载 = 操作符,因为这个等号不是 构造 而是赋值,
// 普通类型可以直接= 但是指针类型需要深拷贝
this->pAddress[i] = arr.pAddress[i];
}
}
// 重载= 操作符 防止浅拷贝问题;等号做赋值传递时,他要返回自身的引用,然后可以做连等操作:arr1 = arr2 = arr3
MyArray& operator=(const MyArray& myarray) { // 返回自身,使用引用&,MyArray&
cout << "调用MyArray的重载operator= -----------------------------" << endl;
// 先判断原来堆区是否有数据,如果有,先释放
if (this->pAddress != NULL) {
delete[] this->pAddress;
this->m_Capacity = 0;
this->m_Size = 0;
}
// 深拷贝;重新在堆区开辟内存
this->m_Capacity = myarray.m_Capacity;
this->m_Size = myarray.m_Size;
this->pAddress = new T[this->m_Capacity];
// 将原数据,添加到新数组中
for (int i = 0; i < this->m_Size; i++) {
this->pAddress[i] = myarray.pAddress[i];
}
return *this; // 将自身做一个返回
}
// 重载[] 操作符 arr[0] = 100;MyArray的对象是自己写的,编译器并不知道对象是啥,所以需要重载
T& operator [](int index) // 返回T,每个元素都是T类型;作为左值存在:arr[0] = 100,需返回引用&
{
//cout << "调用MyArray的重载operator[]" << endl;
return this->pAddress[index]; // 不考虑越界,用户自己去处理
}
// 尾插法
void Push_back(const T& val) //防修改;传入T类型的一个数val,使用引用&
{
// 判断容量是否等于大小;容量满时,不可再插入
if (this->m_Capacity == this->m_Size)
{
return;
}
// 尾部,就是m_Size,数组最后一个;在数组末尾插入数据
this->pAddress[this->m_Size] = val;
// 更新数组大小
this->m_Size++;
}
// 尾删法
void Pop_back()
{
// 让用户访问不到最后一个元素,即为尾删,逻辑删除
if (this->m_Size == 0) // 如果数组个数为0,直接返回,不需要删除
{
return;
}
this->m_Size--; // 数组下标减1,即数组最后一位访问不到;之前最大下标为m_Size,现在为m_Size-1
}
// 获取数组容量
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; // 大小
};
main.cpp中代码:
#include "myArray.hpp" // 包含myArray.hpp文件
#include <string>
void printIntArray(MyArray<int>& arr) { // 直接传入对象的类型MyArray<int>
for (int i = 0; i < arr.getSize(); i++) { // arr.getSize()获取数组大小
cout << arr[i] << " "; // arr[],[]进行了重载,所以不会报错
}
cout << endl;
}
// 测试内置数据类型
void test01()
{
MyArray<int> array1(10); // 模板
for (int i = 0; i < 10; i++)
{
array1.Push_back(i); // 调用尾插法函数,向数组中插入数据
}
cout << "array1打印输出:" << endl;
printIntArray(array1);
cout << "array1的大小:" << array1.getSize() << endl;
cout << "array1的容量:" << array1.getCapacity() << endl;
cout << "--------------------------" << endl;
MyArray<int> array2(array1);
array2.Pop_back();
cout << "array2打印输出:" << endl;
printIntArray(array2);
cout << "array2尾删后的大小:" << array2.getSize() << endl;
cout << "array2尾删后的容量:" << array2.getCapacity() << endl;
}
// 测试自定义数据类型
class Person {
public:
Person() {}
Person(string name, int age) {
this->m_Name = name;
this->m_Age = age;
}
public:
string m_Name;
int m_Age;
};
void printPersonArray(MyArray<Person>& personArr)
{
for (int i = 0; i < personArr.getSize(); i++) {
cout << "姓名:" << personArr[i].m_Name << " 年龄: " << personArr[i].m_Age << endl;
}
}
void test02()
{
// 创建数组
MyArray<Person> pArray(10);
Person p1("孙悟空", 30);
Person p2("韩信", 20);
Person p3("妲己", 18);
Person p4("王昭君", 15);
Person p5("赵云", 24);
// 插入数据
pArray.Push_back(p1);
pArray.Push_back(p2);
pArray.Push_back(p3);
pArray.Push_back(p4);
pArray.Push_back(p5);
printPersonArray(pArray);
cout << "pArray的大小:" << pArray.getSize() << endl;
cout << "pArray的容量:" << pArray.getCapacity() << endl;
}
int main() {
test01();
//test02();
system("pause");
return 0;
}
运行:test01()
运行:test02()