案例要求
可以对内置数据类型以及自定义数据类型的数据进行存储
将数组中的数据存储到堆区
构造函数中可以传入数组的容量
提供对应的拷贝构造函数以及operator=防止浅拷贝问题
提供尾插法和尾删法对数组中的数据进行增加和删除
可以通过下标的方式访问数组中的元素
可以获取数组中当前元素个数和数组的容量
完成步骤
1、封装数组类属性并完成有参构造以及析构函数
#pragma once #include<iostream> using namespace std; template<class t> 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>&hero); private: string name; string position; public: hero() {} hero(string name, string position) { this->name = name; this->position = position; } }; void printarrays(arrays<int>arr) { for (int i = 0; i < arr.getsize(); i++) { cout << arr[i] << " "; } cout << endl; } void printhero(arrays<hero>&hero) { for (int i = 0; i < hero.getsize(); i++) { cout << "姓名:"<<hero[i].name<<" 位置:"<<hero[i].position<<endl; } } void test() { cout << "普通类型数组测试:" << endl; cout << "输入数组容量为:" ; int n = 0; cin >> n; arrays<int> array(n); cout << "输入数据:"; for (int i = 0; i < array.getcapacity(); i++) { int value = 0; cin >> value; array.insert_arrays(value); } cout << "打印数组信息:"<<endl; printarrays(array); array.delete_arrays(); cout << "删除一次尾部数据后打印数组信息:" << endl; printarrays(array); } void test1() { cout << "自定义类型数组测试:" << endl; hero h1("火舞","中单"); hero h2("韩信","打野"); hero h3("桑启","游走"); hero h4("守约","发育"); hero h5("关羽","对抗"); arrays<hero> array(5); array.insert_arrays(h1); array.insert_arrays(h2); array.insert_arrays(h3); array.insert_arrays(h4); array.insert_arrays(h5); printhero(array); array.delete_arrays(); cout << "删除一次尾部数据后打印数组信息:"<<endl; printhero(array); }
首先引入之前封装的数组类头文件,提供printarrays和printhero函数来进行数组信息的打印,test和test1函数分别是整型数组和对象数组的测试。接下来看运行效果。
运行效果:
到此这篇关于c++类模板实战之vector容器的实现的文章就介绍到这了,更多相关c++ vector容器内容请搜索<计算机技术网(www.ctvol.com)!!>以前的文章或继续浏览下面的相关文章希望大家以后多多支持<计算机技术网(www.ctvol.com)!!>!
需要了解更多c/c++开发分享C++类模板实战之vector容器的实现,都可以关注C/C++技术分享栏目—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/1121006.html