IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 学习之类模板案例 - 实现一个通用的数组类(综合性较强) -> 正文阅读

[C++知识库]C++ 学习之类模板案例 - 实现一个通用的数组类(综合性较强)

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

  • 可以对内置数据类型以及自定义数据类型的数据进行存储
  • 将数组中的数据存储到堆区
  • 构造函数中可以传入数组的容量
  • 提供对应的拷贝构造函数以及operator=防止浅拷贝问题
  • 提供尾插法和尾删法对数组中的数据进行增加和删除
  • 可以通过下标的方式访问数组中的元素
  • 可以获取数组中当前元素个数和数组的容量

小总结:“拷贝构造” 和 "=赋值操作 " 如果遇到有在堆区开辟的数据,都会有浅拷贝的问题,要写成深拷贝避免重复释放内存。
具体写法见以下代码:

1、第一版测试代码:

myarray.hpp: 包含类模板的头文件写法
#ifndef _MYARRAY_HPP_//防止头文件重复包含
#define _MYARRAY_HPP_

#include<iostream>
#include<string>
using namespace std;

template<class T>
class MyArray
{
public:
	MyArray(int Capacity)//有参构造函数
	{
		cout << "有参构造函数调用" << endl;
		this->m_Capacity = Capacity;
		this->m_Size = 0;//初始化数组中元素个数为0
		this->pAddress = new T[this->m_Capacity];//开辟对应数据类型的空间	
	}


	MyArray(const MyArray& arr)//1、自己写拷贝构造函数 防止浅拷贝问题
	{
		cout << "拷贝构造函数调用" << endl;
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		//this->pAddress = arr.pAddress;//编译器提供的,指针简单赋值,最后会导致重复释放内存

		this->pAddress = new T[this->m_Capacity];//深拷贝

		for (int i = 0; i < m_Size; i++)//原来数组中可能已经有数据了,所以要把数据都拷贝过来
		{
			this->pAddress[i] = arr.pAddress[i];
		}
	}


	MyArray& operator=(const MyArray& myarray)//2、重载= 运算符 防止浅拷贝问题
	{
		cout << "=赋值函数调用" << 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;//返回对象本身,形成链式编程
	}


	int getCapacity()//获取数组的容量
	{
		return this->m_Capacity;
	}

	int getSize()//获取数组的大小
	{
		return this->m_Size;
	}


	~MyArray()//析构函数
	{
		cout << "析构函数调用" << endl;
		if (pAddress != NULL)
		{
			delete[] pAddress;
			pAddress = NULL;
			this->m_Capacity = 0;
			this->m_Size = 0;
		}
	}


public:
	T* pAddress;   //指向一个堆空间,这个空间存储真正的数据,传进来什么样的数据类型,就开辟对应类型的空间
	int m_Capacity;//数组容量,一共可以存储多少个数据
	int m_Size;    //数组中元素的个数,存完之后数组的元素个数

};

#endif // !_MYARRAY_HPP_

主cpp:
#include<iostream>
#include<string>
#include"myarray.hpp"//包含类模板头文件
using namespace std;

int main()
{
	/*先简单测试一下*/

	MyArray<int> arr1(10);//调用有参构造

	MyArray<int> arr2(arr1);//调用拷贝构造

	MyArray<int> arr3(10);//赋值操作
	arr3 = arr1;

	return 0;
}


现象:

在这里插入图片描述

2、第二版实现功能代码:

myarray.hpp :
#ifndef _MYARRAY_HPP_//防止头文件重复包含
#define _MYARRAY_HPP_

#include<iostream>
#include<string>
using namespace std;

template<class T>
class MyArray
{
public:
	MyArray(int Capacity)//有参构造函数
	{
		this->m_Capacity = Capacity;
		this->m_Size = 0;//初始化数组中元素个数为0
		this->pAddress = new T[this->m_Capacity];//开辟对应数据类型的空间	
	}


	MyArray(const MyArray& arr)//1、自己写拷贝构造函数 防止浅拷贝问题
	{
		if (this->pAddress != NULL) //先判断原来堆区是否有数据,如果有先释放
		{
			delete[] this->pAddress;
			this->m_Capacity = 0;
			this->m_Size = 0;
		}

		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		//this->pAddress = arr.pAddress;//编译器提供的,指针简单赋值,最后会导致重复释放内存

		this->pAddress = new T[this->m_Capacity];//深拷贝

		for (int i = 0; i < m_Size; i++)//原来数组中可能已经有数据了,所以要把数据都拷贝过来
		{
			this->pAddress[i] = arr.pAddress[i];
		}
	}


	MyArray& operator=(const MyArray& myarray)//2、重载= 运算符 防止浅拷贝问题
	{
		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;//返回对象本身,形成链式编程
	}


	T& operator[](int index)//重载[]运算符,实现用下标方式访问数组  例如:arr[1]=100;
	{
		return this->pAddress[index];  //注意返回值的类型要为引用,即返回一个地址,它要作为左值存在,因为你可以修改他的值嘛
	}


	void Push_back(T& data)//尾插法 向数组中插入数据
	{
		//插入之前先判断一下数组是否还有空间,容量是否等于大小
		if (this->m_Capacity == this->m_Size)
		{
			cout << "数组没有空间了" << endl;
			return;
		}

		this->pAddress[this->m_Size] = data;//在数组末尾插入数据,即尾插
		this->m_Size++;//更新数组大小
	}


	void Pop_back()//尾删法  每调用一次,就从数组最后删除一个数据
	{
		//删除之前要判断一下,数组的状态,如果数组中已经没有数据了,那就没法删了
		if (this->m_Size == 0)
		{
			cout << "数组中已没有数据,无法删除" << endl;
			return;
		}
		this->m_Size--;//把数组的大小减一,往前移一个位置让用户访问不到就可以了,即为逻辑删除
	}



	int getCapacity()//获取数组的容量
	{
		return this->m_Capacity;
	}

	int getSize()//获取数组的大小
	{
		return this->m_Size;
	}


	~MyArray()//析构函数
	{
		if (pAddress != NULL)
		{
			delete[] pAddress;
			pAddress = NULL;
			this->m_Capacity = 0;
			this->m_Size = 0;
		}
	}


private:
	T* pAddress;   //指向一个堆空间,这个空间存储真正的数据,传进来什么样的数据类型,就开辟对应类型的空间
	int m_Capacity;//数组容量,一共可以存储多少个数据
	int m_Size;    //数组中元素的个数,存完之后数组的元素个数; 当前数组的大小

};

#endif // !_MYARRAY_HPP_
主cpp :
#include<iostream>
#include<string>
#include"myarray.hpp"//包含类模板头文件
using namespace std;


void PrintInt(MyArray<int>& array)//将打印整型数组元素封装成一个函数
{
	for (int i = 0; i < array.getSize(); i++)
	{
		cout << array[i] << " ";
	}
	cout << endl;
}


void test01()
{
	/*先简单测试一下基本功能*/

	MyArray<int> arr1(10);//调用有参构造
	cout << arr1.getCapacity() << endl;
	cout << arr1.getSize() << endl;

	MyArray<int> arr2(arr1);//调用拷贝构造
	cout << arr2.getCapacity() << endl;
	cout << arr2.getSize() << endl;

	MyArray<int> arr3(10);//赋值操作
	arr3 = arr1;
}


void test02()
{
	/*测试往数组里边存整型数据*/

	MyArray<int> arr(10);//设置数组的容量大小

	for (int i = 0; i < 10; i++)//往数组中插入数据
	{
		arr.Push_back(i);
	}

	arr[0] = 100;//设置数组中第一个元素值为100

	arr.Pop_back();//删除一个元素

	PrintInt(arr);//打印数组中的数据

	cout << "----------------------------" << endl;

	MyArray<int> arr2(arr);//调用拷贝构造复制arr的值

	arr2.Pop_back();

	cout << "数组容量:" << arr2.getCapacity() << " " << "数组大小:" << arr2.getSize() << endl;

	PrintInt(arr2);//打印数组中的数据

}



/*测试自定义数据类型的在数组中的存储*/
class Person
{
public:
	Person()
	{
		//cout << "默认构造调用" << endl;
	}

	Person(string name, int age)
	{
		//cout << "有参构造调用" << endl;
		m_name = name;
		m_age = age;
	}

	~Person()
	{
		//cout << "析构调用" << endl;
	}

public:
	string m_name;
	int m_age;
};


void PrintPerson(MyArray<Person>& p)//将打印Person类型数组封成一个函数
{
	for (int i = 0; i < p.getSize(); i++)
	{
		cout << p[i].m_name<<" "<<p[i].m_age << endl;
	}	
}

void test03()
{
	/*测试自定义数据类型*/

	MyArray<Person> parray(10);//创建Person类型的数组,并声明数组容量

	Person p1("张三", 20);
	Person p2("李四", 21);
	Person p3("王五", 22);
	Person p4("赵六", 23);

	parray.Push_back(p1);
	parray.Push_back(p2);

	cout << "容量:" << parray.getCapacity() << " " << "大小:" << parray.getSize() << endl;

	PrintPerson(parray);

}



int main()
{
	test01();//测试基本功能

	test02();//测试int类型数组

	test03();//测试自定义Perosn类型数组

	return 0;
}

总结:
这个案例综合性还是比较强的,通过做这个案例,把之前的运算符重载,拷贝构造,类模板知识都复习了一遍,这个案例以后还是经常多敲几遍比较好,巩固一下

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-16 19:28:07  更:2021-10-16 19:30:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 19:08:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计