您当前的位置: 首页 >  容器

微凉秋意

暂无认证

  • 0浏览

    0关注

    110博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

C++类模板实战之手写精简版vector容器,详解版

微凉秋意 发布时间:2022-07-04 07:16:28 ,浏览量:0

✨引言

        上一篇博客讲了类模板的基本使用,那么这篇博客就来做一个类模板实战。让我们自己封装一个数组类,可以适应基本数据类型和自定义数据类型。

        《C++提高编程》专栏主要针对C++泛型编程和STL技术做详细讲解,深入研究C++的使用,对C/C++感兴趣的小伙伴可以订阅专栏共同学习,专栏还在持续更新中✨

✨目录

案例要求

完成步骤

1、封装数组类属性并完成有参构造以及析构函数

2、提供对应的深拷贝构造函数防止调用析构时出错

3、重载类内的赋值运算符防止浅拷贝问题出现

4、提供尾部插入和删除的方法

5、重载[]得到数组中对应下标的数据信息

6、提供get方法获取当前数组容量及大小

7、提供打印函数测试基本数据类型和自定义数据类型的存储

✨总结 

案例要求
  • 可以对内置数据类型以及自定义数据类型的数据进行存储
  • 将数组中的数据存储到堆区
  • 构造函数中可以传入数组的容量
  • 提供对应的拷贝构造函数以及operator=防止浅拷贝问题
  • 提供尾插法和尾删法对数组中的数据进行增加和删除
  • 可以通过下标的方式访问数组中的元素
  • 可以获取数组中当前元素个数和数组的容量
完成步骤 1、封装数组类属性并完成有参构造以及析构函数
#pragma once
#include
using namespace std;
template
class Arrays
{
private:
	T* arr;//数组arr存放T类型的数据
	int capacity;//数组容量
	int size;//数组大小
public:
	Arrays(int capacity)
	{
		this->capacity = capacity;
		this->size = 0;
		this->arr = new T[this->capacity];
	}
	~Arrays()
	{
		if (this->arr != NULL)
		{
			delete []this->arr;
			this->arr = NULL;
		}
	}
};

        我把自己的这个数组类模板放到一个.hpp文件里,方便测试的时候调用。代码第一行是为了防止头文件重复包含,template里面的T就是数组的数据类型,根据调用时不同的指定存放不同类型的数据。将数组arr以及数组容量和大小进行封装,写在私有权限下即可 。然后提供该类的有参构造,参数列表传入的是数组容量,有参构造初始化了数组的容量以及大小并将数组开辟到了堆区。析构函数就是来清理堆区数据,如果我们开辟的堆区数组不为空,那就清理掉并将其指向NULL,这样可以防止野指针出现,避免异常。

2、提供对应的深拷贝构造函数防止调用析构时出错
    Arrays(const Arrays& p)
	{
		this->capacity = p.capacity;
		this->size = p.size;
		this->arr = new T[p.capacity];
		for (int i = 0; i < this->size; i++)
		{
			this->arr[i] = p.arr[i];
		}
	}

        如果不提供深拷贝,那么编译器就会有:this->arr=p->arr 这行代码 ,那么一旦我们调用编译器提供的浅拷贝,当运行到析构函数时,就会出现重复删除地址的情况,必然会出现程序错误。所以我们要自己提供深拷贝构造函数,将上面的代码改为 this->arr= new T[p.capacity] ,这样调用析构的时候各自删除各的堆区数据,不会出现上述情况。最后利用for循环将传进来的对象的数据赋值给新开辟的数组。

3、重载类内的赋值运算符防止浅拷贝问题出现
    Arrays& operator=(const Arrays& p)
	{
		if (this->arr!=NULL)
		{
			delete []this->arr;
			this->arr = NULL;
			this->capacity = 0;
			this->size = 0;
		}
        //深拷贝过程
		this->capacity = p.capacity;
		this->size = p.size;
		this->arr = new T[this->capacity];
		for (int i = 0; i < p.size; i++)
		{
			this->arr[i] = p.arr[i];
		}
		return *this;
	}

        当数组数据是对象的类型时,不能简单的将数组进行赋值操作,因为也牵扯到直接赋值出现一样的数组地址的情况,存在着深浅拷贝问题。赋值的时候是将传入参数的数据赋值给自己,因此先把自己的属性清空,然后就是深拷贝的实现了。最后返回的是*this,this指针能够指向不同成员属性,那么*this就是对象本身,然后看到返回值类型是对象引用,这样就可以实现对象间的连续赋值了。

4、提供尾部插入和删除的方法
    void insert_Arrays(const T&value)
	{
		if (this->capacity == this->size)
		{
			return;
		}
		this->arr[size] = value;
		this->size++;
	}
	void delete_Arrays()
	{
		if (this->size == 0)
		{
			return;
		}
		this->size--;
	}

        尾插过程:先判断数组是否已经满了,如果不满就将形参赋值给当前数组最后一个下标的位置,然后更新数组下标,这样就能保证每次插入的数据都在数组末尾。 

        尾删的实现:先判断数组是否为空,不为空的时候直接把数组大小减一即可,让编译器访问不到当前的最后一个数组元素。注意尾删的只是数据的指针,数组的地址并未删除。

5、重载[]得到数组中对应下标的数据信息
    T& operator[](int index)
	{
		return this->arr[index];
	}

       如果数组内容是对象类型,是不存在对象数组的,所以要对[]运算符进行重载。返回值类型为数据类型的引用,也就是具体的数组内的值,传进去的整型参数就是数组下标。

6、提供get方法获取当前数组容量及大小
    int getSize()
	{
		return this->size;
	}
	int getCapacity()
	{
		return this->capacity;
	}

        这里就是经典的get方法了,返回对应封装的成员属性 ,不做多解释。

7、提供打印函数测试基本数据类型和自定义数据类型的存储
#include"arrays.hpp"
class Hero
{
	friend void printHero(Arrays&hero);
private:
	string name;
	string position;
public:
	Hero() {}
	Hero(string name, string position)
	{
		this->name = name;
		this->position = position;
	}
};
void printArrays(Arraysarr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout             
关注
打赏
1664596500
查看更多评论
0.0356s