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

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

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

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

//自己的通用的数组类
#include <iostream>
using namespace std;template<typename T>
class MyArray{public://有参构造函数 参数 容量MyArray(int capacity){cout<<"MyArray有参构造调用"<<endl;this->m_Capacity=capacity;//数组初始化的大小为0this->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=cMyArray &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这个文件里面写入下面的代码

#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

//自己的通用的数组类
#include <iostream>
using namespace std;template<typename T>
class MyArray{public://有参构造函数 参数 容量MyArray(int capacity){this->m_Capacity=capacity;//数组初始化的大小为0this->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=cMyArray &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;//数组的元素个数(数组的大小)
};

数组类封装函数那里写

#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表示程序正常结束
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/89316.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/89316.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/89316.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器端安全检测与防御技术概述

一、服务器安全风险1.不必要的访问&#xff08;如只提供HTTP服务&#xff09;--应用识别控制2.公网发起IP或端口扫描、DDOS攻击等--防火墙3.漏洞攻击&#xff08;针对服务器操作系统等&#xff09;--IPS4.根据软件版本的已知漏洞进行攻击&#xff0c;口令暴力破解、获取用户权限…

前端性能与可靠性工程系列: 渲染、缓存与关键路径优化

前端性能与可靠性工程系列: 渲染、缓存与关键路径优化 第一部分:揭秘浏览器 - 关键渲染路径 (CRP) 关键渲染路径 (Critical Rendering Path - CRP) 是指浏览器从接收到最初的 HTML、CSS 和 JavaScript 字节,到最终将它们渲染成可见像素所必须经过的一系列步骤。我们的目标,…

基于CentOS的分布式GitLab+Jenkins+Docker架构:企业级CI/CD流水线实战全记录

引言&#xff1a;从单机到分布式容器架构的演进在传统Web应用部署中&#xff0c;我们常常面临环境不一致、部署效率低下等问题。我曾经维护过一个需要手动在5台服务器上重复部署的游戏项目&#xff0c;每次发布都如同走钢丝。本文将详细分享如何基于CentOS系统&#xff0c;构建…

JVM——为什么Java8移除了永久代(PermGen)并引入了元空间(Metaspace)?

Java8移除永久代并引入元空间&#xff0c;主要是为了解决 PermGen 固定大小、容易导致内存溢出、GC 效率低的问题。元空间使用本地内存&#xff0c;具备更灵活的内存分配能力&#xff0c;提升了垃圾收集和内存管理的效率。 PermGen 的局限性 ①固定大小:永久代的内存空间大小在…

3.正则化——新闻分类

影响结果出了最终的目标&#xff0c;还会有许多细节因素 在机器学习中&#xff0c;往往会面临很多过拟合和欠拟合的问题。 欠拟合是训练不到位&#xff0c;过拟合是训练过头&#xff0c;会导致泛化性差正则化是在损失函数中添加一个惩罚项&#xff0c;以简化模型对于惩罚项Pena…

HTML的重要知识

什么是HTMLHTML是Hyper Text Markup Language的缩写&#xff0c;意思是超文本标记语言。标签标题标签&#xff1a;————-h1,h2,h3.....段落标签 &#xff1a;————p换行标签&#xff1a; ————br列表标签&#xff1a;有序列表&#xff1a;——ol无序列表&#xff1a;—…

【C语言网络编程】HTTP 客户端请求(发送请求报文过程)

在 C 语言中&#xff0c;我们可以使用 socket 编程来手动实现一个简单的 HTTP 客户端&#xff0c;像浏览器一样请求网页数据。本文将结合实际代码&#xff0c;重点讲解如何通过 C 语言构造并发送一个 HTTP 请求报文&#xff0c;实现与服务器的基本通信。 文章目标 通过一个简单…

oracle2kingbase的字段长度问题

实验一&#xff1a; oracle中&#xff1a; create table testlen(c1 varchar2(2)); insert into testlen values(山); --成功 insert into testlen values(山西); --失败 ORA-12899: 列 "TESTK"."TESTLEN"."C1" 的值太大 (实际值: 4, 最大值: 2…

单链表的题目,咕咕咕

1.咕 203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 struct ListNode* removeElements(struct ListNode* head, int val) …

关于程序=数据结构+算法这句话最近的一些思考

最近看了很多单片机STM32的的相关程序&#xff0c;尤其是设计到ringbuff、buffer_manage、os_memory预计mem_manage等程序中间层的用法&#xff0c;我对这句话有了一些更深的思考&#xff0c;现在记录下来&#xff0c;希望对处于相同阶段的程序一些思想启迪。首先“数据结构”也…

Rust 错误处理

Rust 错误处理 引言 Rust 是一种系统编程语言&#xff0c;以其安全、并发和性能著称。在 Rust 中&#xff0c;错误处理是一个核心概念&#xff0c;它确保了程序在遇到异常情况时能够优雅地处理。本文将深入探讨 Rust 中的错误处理机制&#xff0c;包括错误类型、错误传播、错误…

17. 什么是 webSocket ?

总结 WebSocket 是 HTML5 引入的一种新协议&#xff0c;允许客户端和服务器之间进行双向实时通信。建立在 TCP 协议之上&#xff0c;默认端口是 80&#xff08;ws&#xff09; 和 443&#xff08;wss&#xff09;&#xff0c;没有同源限制&#xff0c;客户端可以与任意服务器通…

从零开始跑通3DGS教程:(五)3DGS训练

写在前面 本文内容 所属《从零开始跑通3DGS教程》系列文章; 本文介绍在docker中训练3dgs的方法 平台/环境 linux, nvidia GPU, docker 转载请注明出处: https://blog.csdn.net/qq_41102371/article/details/146535874 目录 写在前面系列文章准备docker创建环境参考完系列文章…

日记_7.14_实际开发的进步

1、快速定位后端2、会定位前端啦啦啦&#xff01;3、前端没有意义的块叫div和span。而不是script4、所有 JavaScript 标识符均 区分大小写5、JS中$和_下划线和doller符均被视为字母。6、var、let区别&#xff1a;1 var全局。let局部。2 var可以重新声明格式&#xff0c;let之恩…

AI Agent 开发

Agent开发常用框架&#xff1a; LangChainLlamaIndexVercel AI SDK LangChain&#xff1a;一站式 LLM 应用开发框架一句话总结 LangChain 把「模型调用 外部数据 工具 记忆 流程编排」全部标准化&#xff0c;让你像搭积木一样快速组合出聊天机器人、RAG、Agent 等大模型应用…

【水动力学】04 二维洪水淹没模型Pypims安装

模型介绍 HiPIMS&#xff08;High-Performance Integrated hydrodynamic Modelling System&#xff09;使用最先进的数值方案&#xff08;Godunov型有限体积法&#xff09;来求解二维浅水方程以进行洪水模拟。为了支持高分辨率洪水模拟&#xff0c;使用CUDA/C 语言在多个GPU上…

ARC 03 从Github Action job 到 runner pod

Github Action job 分配到集群 背景 job 是 Github Action 的基本单位&#xff0c;每个 job 单独分配一个 runner。workflow 由一个或者多个 job 组成。如果用户触发runs-on字段为arc-runner-set的 job&#xff0c;那么 Github Action 服务器将 job 分配给 listener pod。 源码…

ubuntu 22.04 anaconda comfyui安装

背景&#xff1a; 戴尔R740服务器&#xff0c;安装了proxmox操作系统&#xff0c;配置了显卡直通。创建了一个ubuntu 22.04 VM虚拟机实例&#xff0c;并安装了显卡驱动与cuda等相关配置&#xff1a; 接下来准备搭建一套comfyui的环境&#xff0c;前段时间B站&#xff0c;抖音各…

每日面试题04:volatile字段的原理

在之前面试题02ConcurrentHashMap的底层原理中提到了volatile修饰符&#xff0c;在多线程编程的世界里&#xff0c;数据同步是一道绕不开的坎。当多个线程同时操作共享变量时&#xff0c;“看不见对方的修改”或“代码顺序错乱”往往会导致程序行为异常。而 volatile作为 Java …

【云原生网络】Istio基础篇

文章目录概述基础知识技术架构概述数据平面核心组件网络代理Envoy控制平面核心组件xDS协议Pilot组件其他概述参考博客&#x1f60a;点此到文末惊喜↩︎ 概述 基础知识 背景知识 服务网格&#xff08;Service Mesh&#xff09;&#xff1a;独立于应用程序的基础设施层&#x…