C++类模板实战之vector容器的实现

目录
  • 案例要求
  • 完成步骤
    • 1、封装数组类属性并完成有参构造以及析构函数
    • 2、提供对应的深拷贝构造函数防止调用析构时出错
    • 3、重载类内的赋值运算符防止浅拷贝问题出现
    • 4、提供尾部插入和删除的方法
    • 5、重载[]得到数组中对应下标的数据信息
    • 6、提供get方法获取当前数组容量及大小
    • 7、提供打印函数测试基本数据类型和自定义数据类型的存储

案例要求

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

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

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

提供对应的拷贝构造函数以及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容器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++中vector容器使用详细说明

    在c++中,vector是一个十分有用的容器,下面通过本文给大家介绍C++中vector容器使用详细说明,具体介绍如下所示 1. 在C++中的详细说明 vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库. vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据. 2. 使用vector,必须在你的头文件中包含下面的代码: #include vec

  • C++之vector容器的的声明初始化和增删改查

    C++vector容器 C++中有两种类型的容器:顺序容器和关联容器. 顺序容器主要有vector.list.deque等.其中vector表示一段连续的内存,基于数组实现,list表示非连续的内存,基于链表实现,deque与vector类似,但是对首元素提供插入和删除的双向支持. 关联容器主要有map和set.map是key-value形式,set是单值.map和set只能存放唯一的key,multimap和multiset可以存放多个相同的key. 容器类自动申请和释放内存,因此无需new和

  • C++ 容器 Vector 的使用方法

    目录 Vector简介 Vector 与数组 创建 vector 的各种方法 访问 vector 的元素 删除元素 前言: 我们都是带着问题学习,假设一个任务,也可以理解为一个问题,通过找解决方案来提升自己 c++ 的编程能力,尝试这是否一条好的路线,希望找到这种学习方式有效 问题简单描述一下,就是从以字符串,课程名称组成的集合中将一些包含特定文字,将其从列表中删除 Vector简介 Vector 是一个能够存放任意类型的动态数组,有点类似数组,是一个连续地址空间, Vector 与数组 Vec

  • C++示例讲解vector容器

    目录 vector基本概念 创建 vector 的各种方法 vector容器的构造 vector赋值操作 vector容量和大小 vector容器插入和删除 vector数据存取 vector互换容器 vector基本概念 功能: vector数据结构和数组非常相似,也称为单端数组 vector与普通数组区别: 不同之处在于数组是静态空间,而vector可以动态扩展 动态扩展: 并不是在原空间之后继续接新空间,而是找更大的内存空间,然后将元数据拷贝新空间,释放原空间 创建 vector 的各种方

  • C++中vector容器的用法

    在c++中,vector是一个十分有用的容器,下面对这个容器做一下总结. 1 基本操作 (1)头文件#include<vector>. (2)创建vector对象,vector<int> vec; (3)尾部插入数字:vec.push_back(a); (4)使用下标访问元素,cout<<vec[0]<<endl;记住下标是从0开始的. (5)使用迭代器访问元素. vector<int>::iterator it; for(it=vec.begi

  • C++中vector容器的常用操作方法实例总结

    1 获得容器最后一个元素  ------ 使用 back或rbegin 取得 // back.rbegin 有常量和引用两种形式 std::vector<int> myVector; myVector.back()=3; std::vector<int>::reverse_iterator tailIter; tailIter=myVector.rbegin(); *tailIter=3 2 删除某元素 需要删除某位置的元素,应使用iterator遍历, 不应使用at(i) 方式遍

  • C++类模板实战之vector容器的实现

    目录 案例要求 完成步骤 1.封装数组类属性并完成有参构造以及析构函数 2.提供对应的深拷贝构造函数防止调用析构时出错 3.重载类内的赋值运算符防止浅拷贝问题出现 4.提供尾部插入和删除的方法 5.重载[]得到数组中对应下标的数据信息 6.提供get方法获取当前数组容量及大小 7.提供打印函数测试基本数据类型和自定义数据类型的存储 案例要求 可以对内置数据类型以及自定义数据类型的数据进行存储 将数组中的数据存储到堆区 构造函数中可以传入数组的容量 提供对应的拷贝构造函数以及operator=防止

  • 关于STL中vector容器的一些总结

    1.vector的简单介绍 vector作为STL提供的标准容器之一,是经常要使用的,有很重要的地位,并且使用起来也是灰常方便.vector又被称为向量,vector可以形象的描述为长度可以动态改变的数组,功能和数组较为相似.实际上更专业的描述为:vector是一个多功能的,能够操作多种数据结构和算法的模板类和函数库,vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据.(注:STL的容器从实现的

  • C++中的vector容器对象学习笔记

    C++中数组很坑,有没有类似Python中list的数据类型呢?类似的就是vector! vector 是同一种类型的对象的集合 ,每个对象都有一个对应的整数索引值.和 string 对象一样,标准库将负责管理与存储元素相关的内存. 我们把 vector 称为容器,是因为它可以包含其他对象 . 一个容器中的所有对象都必须是同一种类型的 . vector对象的定义和初始化 同样的,使用前,导入头文件#include <vector> 可以使用using声明:using std::vector;

  • C++ vector容器 find erase的使用操作:查找并删除指定元素

    概念:容器.迭代器.算法 STL包括容器.迭代器和算法: 容器 用于管理一些相关的数据类型.每种容器都有它的优缺点,不同的容器反映出程序设计的不同需求.容器自身可能由数组或链表实现,或者容器中的每个元素都有特殊的关键值. 迭代器 用于遍历一个数据集中的每个元素.这些数据集可能是容器或者容器的子集.迭代器的主要优点是它们为任意类型的容器提供一个小巧并且通用(注意通用很重要)的接口.例如,迭代器接口的一个操作是让它依次遍历数据集的每个元素.这个操作是依赖容器的内总部结构独立完成的.迭代器之所以有效是

  • C++入门笔记之std::vector容器详解

    目录 前言 1. vector的构造函数原型: 2. vector的赋值函数原型: 3. vector的容量和大小函数原型: 4. vector的插入和删除函数原型: 5. vector的存取操作函数原型: 6. vector的呼唤容器函数原型: 总结 前言 vector实质是C++的一个类,与数组很相似,但是vector的优势是可以动态扩展,不需要考虑其内存大小. 定义: 向量(Vector)是一个封装了动态大小数组的顺序容器(Sequence Container).跟任意其它类型容器一样,它

  • C++模板以及实现vector实例详解

    目录 函数模板 类模板 Vector实现 简单的类模板实现代码及测试: win msvc编译器的实现: 容器的空间配置器 运算符重载与迭代器实现 最终vector的实现代码 总结 函数模板 函数模板:是不进行编译的,因为类型还不知道 模板的实例化:函数调用点进行实例化 模板函数:才是要被编译器所编译的 模板类型参数:typyname/class 模板非类型参数:模板非类型形参的详细阐述 模板的实参推演:可以根据用户传入的实参的类型,来推导出模板类型参数的具体 模板的特例化(专用化)的实例化 模板

  • C++中vector容器的注意事项总结

    目录 容量(capacity)和大小(size)的区别 容器扩容的本质 emplace_back()和push_back()的区别 emplace()和insert()的区别 附:如果vector是空的,并且没有分配空间,切忌用下标进行访问,会出错!!! 总结 容量(capacity)和大小(size)的区别 vector 容器的容量(用 capacity 表示),指的是在不分配更多内存的情况下,容器可以保存的最多元素个数:而 vector 容器的大小(用 size 表示),指的是它实际所包含的

  • C++详细讲解互斥量与lock_guard类模板及死锁

    目录 互斥量的基本概念 互斥量的使用 lock_guard类模板 死锁 lock与lock_guard的使用 保护共享数据,操作时,用代码把共享数据锁住.操作数据.解锁 其他想操作共享数据的线程必须等待解锁.锁定住.操作.解锁 互斥量的基本概念 互斥量是个类对象,理解成一把锁,多个线程尝试使用lock()成员函数来枷锁这个锁,是有一个线程可以锁成功,成功的标志是返回 如果没有锁成功,那么流程卡在lock这里不断尝试去锁 互斥量的使用 #include <iostream> #include &

  • C++函数模板与类模板实例解析

    本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程(Generic Programming)是一种编程范式,通过将类型参数化来实现在同一份代码上操作多种数据类型,泛型是一般化并可重复使用的意思.泛型编程最初诞生于C++中,目的是为了实现C++的STL(标准模板库). 模板(template)是泛型编程的基础,一个模板就是一个创建类或函数的蓝图或公式.例如,当使用一个vector这样的泛型类型或者find这样的泛型函数

随机推荐