C++模板笔记十:类模板案例:通用数组类

C++模板笔记十:类模板案例:通用数组类,第1张

C++模板笔记十:类模板案例:通用数组

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

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

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

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

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

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

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

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



需求分析: 一、类的基本结构:

设计一个MyArray的类,类内属性为:

类内维护一个数组:T* item = new T[5];维护表示一个关于数组容量的属性:m_Capacity。维护表示一个数组元素个数的属性:m_Size。

属性写为private权限。

二、数据结构:

维护的这个数组要开辟到堆区。在堆区中维护的这个数据类型必须是通用的,即泛型的,支持多样性。所以堆中数组元素类型为T。

为此:数组中每个元素为 T* item = new T[5];

三、接口功能:

对外要提供一些功能函数接口:public:

构造函数(传入容量):传入参数,指定数组的容量。拷贝构造:operator=:运算符重载。类内存在堆区的数据,为了防止 浅拷贝重复释放 的问题。利用下标的方式:访问数组元素尾插法:尾删法:获取数组的容量获取数组的元素个数。析构函数:



四:一步步实施:

这个需要内容比较多,不适合写在一个文件里面,所以分文件写:类模板分文件的编写,最好将声明和实现写在一起:都放在.hpp文件中。

先写一个类模板的文件:MyArray.hpp文件。

#include
using namespace std;

template
class MyArray
{
public:
	// 初始化:有参构造 参数 容量
	MyArray(int capacity)
	{
		this->m_Capacity = capacity;
		this->m_Size = 0;
		this->pAddress = new T[this->m_Capacity];

		// 测试代码:
		cout << "MyArray 有参构造 被调用。" << endl;
	}

	// 拷贝构造
	MyArray(const MyArray& arr)
	{
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		
		//this->pAddress  // 开辟在堆区,所以需要深拷贝,从堆中,重新开辟一块空间,拷贝过去。
		this->pAddress = new T[arr.m_Capacity];
		// 将arr中的数据都拷贝过来。
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
		cout << "MyArray 拷贝构造 被调用。" << endl;
	}

	// 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 < arr.m_Capacity; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
		cout << "MyArray 运算符重载operator= 被调用。" << endl;
		return *this;   // 返回自身。
	}

	// 析构函数:
	~MyArray()
	{
		if (this->pAddress!=NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;    // 置空,防止称为野指针。
			cout << "MyArray 析构函数 被调用。" << endl;
		}
	}

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

先把基本框架写出来,然后做个测试:在程序中写一个测试案例。补充打印测试。

先包含头文件:#include "MyArray.hpp"

void test01()
{
	int len = 5;
	MyArray arr(len);
	MyArray arr1(arr);  // 拷贝构造方式。
	MyArray arr2(10);
	arr2 = arr;              // 运算符重载。

}

阶段性测试:已经完成前面几个任务,只剩下最后三个任务:

先写:尾插法、尾删法

// 尾插法
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--;
}

下标访问:

// 下标访问元素:返回类型为元素类型T,如果需要将返回值作为左值存在,那么需要返回引用。
T& operatoar[](int index)
{
	return this->pAddress[index];
}

返回数组容量、大小

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

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

为了打印输出,我写了个友元来显示每一项:

friend void printArray(const MyArray& arr)
{
	for (int i = 0; i < arr.m_Size; i++)
	{
		cout << arr.pAddress[i] << " ";
	}
	cout << endl;
}
void test01()
{
	int len = 5;
	MyArray arr(len);
	MyArray arr1(arr);  // 拷贝构造方式。
	MyArray arr2(10);
	arr2 = arr;              // 运算符重载。

}

void test02()
{
	int len = 5;
	MyArray arr(len);
	for (int i = 0; i < len; i++)
	{
		arr.Push_Back(i + 1);
	}
	cout << "初始化arr:";
	printIntArray(arr);  // 友元;
	// 测试尾删法:
	arr.Pop_Back();
	cout << "测尾删arr:";
	printIntArray(arr);  // 友元;

	// 测试尾插法;
	arr.Push_Back(99);
	printIntArray(arr);  // 友元;
	cout << arr.getCapacity() << endl;
	cout << arr.getSize() << endl;

}


以上是关于内置数据类型的案例。来看看自定义类型案例。

#pragma once
#include
using namespace std;


template
class Person
{
public:
	Person() {};    // 不加这个默认构造函数,会报错。
	Person(T1 name, T2 age);
	void showPerson();
private:
	T1 m_Name;
	T2 m_Age;
};

// 类外实现
template
Person::Person(T1 name, T2 age)
{
	this->m_Name = name;
	this->m_Age = age;
}
template
void Person::showPerson()
{
	cout << "姓名:" << this->m_Name << ", 年龄:" << this->m_Age << endl;
}

我们直接套用前面几节中关于Person.hpp的类模板。然后来测试。

void printPersonArray(MyArray>& arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		arr[i].showPerson();
	}
}

// 看看自定义类数组效果
void test03()
{
	Person p1("张三", 18);
	Person p2("李四", 14);
	Person p3("王五", 15);
	Person p4("赵六", 16);
	Person p5("田七", 17);
	MyArray> arr(5);  

	arr.Push_Back(p1);
	arr.Push_Back(p2);
	arr.Push_Back(p3);
	arr.Push_Back(p4);
	arr.Push_Back(p5);
	printPersonArray(arr);

}

报错了;

 没有合适的默认构造函数可用。因此需要在Person.hpp中,将默认构造函数,加进去,即:Person(){}。否则会报上面的错误。

类模板中引用其他类模板,被引用类模板要加上默认构造函数。

此外两个深拷贝存在这样一个问题:待我技术成长了再来解决。

 

 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5718682.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存