类模版的相关案例

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

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

因为我们并不知道里面有什么数据类型,因此我们需要将这些数据进行模版化

首先我们在MyArray.hpp文件里面写入以下的代码

cpp 复制代码
//自己的通用的数组类
#include <iostream>
using namespace std;

template<typename T>
class MyArray{
    public:
        //有参构造函数 参数 容量
        MyArray(int capacity)
        {
            cout<<"MyArray有参构造调用"<<endl;
            this->m_Capacity=capacity;
            //数组初始化的大小为0
            this->m_Size=0;
            this->pAddress=new T[capacity]; //开辟堆区空间
        }
        //为了防止浅拷贝的问题,还必须写一个拷贝构造函数
        MyArray(const MyArray &arr)
        {
            cout<<"MyArray拷贝构造函数调用"<<endl;
            this->m_Capacity=arr.m_Capacity;
            this->m_Size=arr.m_Size;
            //潜拷贝
            //this->pAddress=arr.pAddress; //将原数组的地址赋值给新数组
            //开辟新的堆区空间
            this->pAddress=new T[arr.m_Capacity];
            //将原数组的元素拷贝到新数组中
            for(int i=0;i<this->m_Capacity;i++)
            {
                this->pAddress[i]=arr.pAddress[i];
            }
        }
        //operator= 也是为了防止浅拷贝问题. a=b=c
        MyArray &operator=(const MyArray &arr)
        {
            cout<<"MyArray赋值运算符调用"<<endl;
            //先判断原来堆区是否有数据,如果有先释放
            if(this->pAddress!=nullptr)
            {
                delete[] this->pAddress;
                this->pAddress=nullptr;//防止其为一个野指针
                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<this->m_Size;i++)
            {
                this->pAddress[i]=arr.pAddress[i];//将原数组的元素拷贝到新数组中
            }
            return *this;//返回当前对象的引用
        }
        //之后再去做一个深拷贝

        
        //析构函数
        ~MyArray()
        {
            if(this->pAddress!=nullptr)
            {
                cout<<"MyArray析构函数调用"<<endl;
                delete[] this->pAddress;
                //防止其为一个野指针
                this->pAddress=nullptr;
            }
        }

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

在数组类封装.cpp这个文件里面写入下面的代码

cpp 复制代码
#include <iostream>
using namespace std;
#include "MyArray.hpp"

void test01()
{
    MyArray<int> arr1(5); // 创建一个容量为5的数组
    MyArray<int> arr2(arr1); // 使用拷贝构造函数创建一个新数组
    MyArray<int> arr3(100); // 使用赋值运算符进行赋值
    arr3=arr1;// 使用赋值运算符进行赋值
}

int main()
{
    test01(); // 测试函数
    return 0; // 返回0表示程序正常结束
}

之后运行,我们可以得到以下的内容

也就是说我们这几个进行了深拷贝,还有有参构造,之后通过析构函数释放了它们的内存。

MyArray.hpp

cpp 复制代码
//自己的通用的数组类
#include <iostream>
using namespace std;

template<typename T>
class MyArray{
    public:
        //有参构造函数 参数 容量
        MyArray(int capacity)
        {
            this->m_Capacity=capacity;
            //数组初始化的大小为0
            this->m_Size=0;
            this->pAddress=new T[capacity]; //开辟堆区空间
        }
        //为了防止浅拷贝的问题,还必须写一个拷贝构造函数
        MyArray(const MyArray &arr)
        {
            this->m_Capacity=arr.m_Capacity;
            this->m_Size=arr.m_Size;
            //潜拷贝
            //this->pAddress=arr.pAddress; //将原数组的地址赋值给新数组
            //开辟新的堆区空间
            this->pAddress=new T[arr.m_Capacity];
            //将原数组的元素拷贝到新数组中
            for(int i=0;i<this->m_Capacity;i++)
            {
                this->pAddress[i]=arr.pAddress[i];
            }
        }
        //operator= 也是为了防止浅拷贝问题. a=b=c
        MyArray &operator=(const MyArray &arr)
        {
            //先判断原来堆区是否有数据,如果有先释放
            if(this->pAddress!=nullptr)
            {
                delete[] this->pAddress;
                this->pAddress=nullptr;//防止其为一个野指针
                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<this->m_Size;i++)
            {
                this->pAddress[i]=arr.pAddress[i];//将原数组的元素拷贝到新数组中
            }
            return *this;//返回当前对象的引用
        }
        //尾插法
        //一般为了防止T被修改,因此我们一般会写入一个const修饰符
        void Push_Back(const T &val)
        {
            //判断数组是否已满
            if(this->m_Size>=this->m_Capacity)  
            {
                cout<<"数组已满,无法插入元素"<<endl;
                return;
            }
            else{
                this->pAddress[this->m_Size]=val; //将元素插入到数组的末尾
                this->m_Size++;//元素个数加1
            }
        }
        //尾删法
        void Pop_Back()
        {
            if(this->m_Size<=0)
            {
                cout<<"数组为空,无法删除元素"<<endl;
                return;
            }
            else{
                //让用户访问不到最后一个元素就可以了
                this->m_Size--;//元素个数减1
                //不需要删除最后一个元素,因为数组的大小已经减小了
            }
        }
        //通过下标的方式访问数组中的元素
        T& operator[](int index)
        {
            
            return this->pAddress[index]; //返回数组中指定下标的元素
        }

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

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

        
        //析构函数
        ~MyArray()
        {
            if(this->pAddress!=nullptr)
            {
                delete[] this->pAddress;
                //防止其为一个野指针
                this->pAddress=nullptr;
            }
        }

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

数组类封装函数那里写

cpp 复制代码
#include <iostream>
using namespace std;
#include "MyArray.hpp"
#include <string>


void printIntArray(MyArray<int> &arr)
{
    for(int i=0;i<arr.GetSize();i++)
    {
        cout<<arr[i]<<" "<<endl;
    }
}
void test01()
{
    MyArray<int> arr1(5); // 创建一个容量为5的数组
    for(int i=0;i<5;i++)
    {
        arr1.Push_Back(i); // 向数组中添加元素
    }
    cout<<"arr1的打印输出为:"<<endl;
    // MyArray<int> arr2(arr1); // 使用拷贝构造函数创建一个新数组
    // MyArray<int> arr3(100); // 使用赋值运算符进行赋值
    // arr3=arr1;
    printIntArray(arr1); // 打印数组内容
    cout<<"arr1的容量为:"  << arr1.GetCapacity() << endl; // 打印数组容量 
    cout<<"arr1的大小为:"  << arr1.GetSize() << endl; // 打印数组大小

    MyArray<int> arr2(arr1); // 使用拷贝构造函数创建一个新数组
    cout<<"arr2的打印输出为:"<<endl;
    arr2.Pop_Back(); // 删除数组的最后一个元素
    printIntArray(arr2); // 打印删除后的数组内容
    cout<<"删除一个元素后,arr2的大小为:"  << arr2.GetSize() << endl; // 打印数组大小
    cout<<"删除一个元素后,arr2的容量为:"  << arr2.GetCapacity() << endl; // 打印数组容量

   
}

 //测试自定义的数据类型
    class Person{
        public:

            Person() {}
            Person(string name,int age): m_Name(name),m_Age(age){
                this->m_Name=name;
                this->m_Age=age;
            }
            string m_Name;
            int m_Age;

    };
    void printPersonArray(MyArray<Person> &arr)
    {
        for(int i=0;i<arr.GetSize();i++)
        {
            cout<<"姓名: "<<arr[i].m_Name<<" 年龄: "<<arr[i].m_Age<<endl;
        }
    }

    void test02()
    {
        MyArray<Person> arr3(10);
        Person p1("孙悟空",500);
        Person p2("猪八戒",300);
        Person p3("沙和尚",400);
        Person p4("唐僧",1000);
        Person p5("白龙马",200);
        Person p6("小白龙",150);
        Person p7("小红龙",120);
        arr3.Push_Back(p1);
        arr3.Push_Back(p2);
        arr3.Push_Back(p3);
        arr3.Push_Back(p4);
        arr3.Push_Back(p5);

        arr3.Push_Back(p6);
        arr3.Push_Back(p7); 

        //打印数组
        printPersonArray(arr3); // 这里需要重载printIntArray函数来打印Person类型的数组



    }





int main()
{
    test01(); // 测试函数
    cout << "------------------------" << endl;
    cout << "测试自定义数据类型的数组" << endl;
    cout << "------------------------" << endl;
    cout << "测试自定义数据类型的数组" << endl;
    test02(); // 测试函数
    return 0; // 返回0表示程序正常结束
}
相关推荐
地平线开发者2 小时前
理想汽车智驾方案介绍专题 1 端到端+VLM 方案介绍
算法·自动驾驶
地平线开发者2 小时前
征程 6 | UCP 任务优先级/抢占简介与实操
算法·自动驾驶
杰克尼2 小时前
912. 排序数组
算法
jndingxin3 小时前
OpenCV直线段检测算法类cv::line_descriptor::LSDDetector
人工智能·opencv·算法
秋说3 小时前
【PTA数据结构 | C语言版】阶乘的递归实现
c语言·数据结构·算法
小指纹4 小时前
巧用Bitset!优化dp
数据结构·c++·算法·代理模式·dp·bitset
爱Java&Java爱我5 小时前
数组:从键盘上输入10个数,合法值为1、2或3,不是这三个数则为非法数字,试编辑统计每个整数和非法数字的个数
java·开发语言·算法
是店小二呀6 小时前
【算法-BFS 解决最短路问题】探索BFS在图论中的应用:最短路径问题的高效解法
算法·图论·宽度优先
qq_513970446 小时前
力扣 hot100 Day46
算法·leetcode
满分观察网友z8 小时前
递归与迭代的优雅之舞:我在评论区功能中悟出的“树”之道(104. 二叉树的最大深度)
后端·算法