数组类模板

news2024/11/27 22:42:01

要求:

设计一个数组模板类(MyArray),完成对不同类型元素的管理

操作步骤

设计头文件

在 qtcreate下先创建03_code的项目,然后右键点击03_code添加新文件,点击头文件,点击Choose

命名为 myarry.hpp,其中 .hpp是头文件和源文件结合的一种,一般头文件 .h 是定义类模板,而.cpp 实现类模板的公共方法操作,但是这种方式存在问题,所以为了方便我们操作,C++可以直接使用 .hpp 实现定义类模板和实现它的公共操作方法

设计模板类

#ifndef MYARRY_HPP
#define MYARRY_HPP
#include <iostream>
#include <string.h>
using namespace std;
template <class T>
class MyArry{
    template <typename T1>
    friend ostream & operator<<(ostream &out,MyArry<T1> ob);
private:
    T *arry;  //保存数组地址
    int size; //大小
    int capacity; //容量
public:
    //无参构造
    MyArry();
    //有参构造
    MyArry(int capacity);
    //拷贝构造
    MyArry(MyArry &ob);
    //析构函数
    ~MyArry();
    //重载运算符,完成深拷贝
    MyArry & operator=(MyArry &ob);
    //输入函数
    void pushBack(T elem);
};
#endif // MYARRY_HPP

公共方法实现

无参构造

//无参构造 成员变量初始化
template<class T>
MyArry<T>::MyArry()
{
    arry = NULL;
    size = 0;
    capacity = 0;
}

有参构造

//有参构造 成员变量赋值
template<class T>
MyArry<T>::MyArry(int capacity)
{
    this->capacity = capacity;
    arry = new T[this->capacity];
    size = 0;
    //清空数组
    memset(arry,0,sizeof(T)*capacity);
}

拷贝构造

拷贝构造本质是构造函数

在上面的代码中,旧对象给新对象初始化就会调用拷贝构造函数

目的是为了在结束的时候新对象也会调用析构函数释放掉新创建的堆区空间,而不会造成新旧对象前后释放指针变量指向的同一块堆区空间,造成多次释放

//拷贝构造
template<class T>
MyArry<T>::MyArry(MyArry &ob)
{
    //ob没有空间,拷贝的空间也没有
    if (ob.arry == NULL){
        arry = NULL;
        size = 0;
        capacity = 0;
    }
    //ob有空间,所以即将拷贝的也有空间
    else{
        capacity = ob.capacity;
        size = ob.size;
        //申请堆区数组空间
        arry = new T[capacity];
        //将旧堆区空间的值复制到新堆区空间
        memcpy(arry,ob.arry,sizeof(T)*capacity);
    }
}

析构函数

//析构函数,释放堆区空间
template<class T>
MyArry<T>::~MyArry()
{
    if(arry != NULL){      //若堆区空间为空就不用析构
        delete [] arry;
    }
}

重载运算符,完成 “=”深拷贝

返回值是引用类型是因为可以链式操作完成 “=”深拷贝,即 ........ob3 = ob2 = ob1 = ob,返回值依然是一个 MyArry<T> 类型,MyArry<T> 必不可少,因为它模板类名 MyArry 和 T 一起完整的描述了是一个如何的返回值

//深拷贝的时候完成赋值重载运算符  ob1 = ob2
template<class T>
MyArry<T> &MyArry<T>::operator=(MyArry &ob)
{
    //判断 this->arry是否存在空间
    if(this->arry != NULL){
       delete [] arry;
       arry = NULL;
    }
    capacity = ob.capacity;
    size = ob.size;
    //申请数组堆区空间
    arry = new T[capacity];
    //将旧堆区空间的值复制到新堆区空间
    memset(arry,0,sizeof(T)*capacity);
    //将旧堆区空间的值复制到新堆区空间
    memcpy(arry,ob.arry,sizeof(T)*capacity);
    //链式完成赋值重载运算符,返回左边运算符的引用
    return *this;
}

插入函数

//输入函数
template<class T>
void MyArry<T>::pushBack(T elem)
{
    if (size == capacity){  //满
        //扩展容量
        capacity = (capacity == 0?1:2*capacity);
        //根据容量申请空间
        T *temp = new T[capacity];
        //无参构造没有给空间的代价,因为无参构造中 size == capacity
        if(arry != NULL){
            //将旧空间的内容拷贝到新空间
            memcpy(temp,arry,sizeof(T)*size);
            //释放旧空间
            delete [] arry;
        }
        arry = temp;
    }
    arry[size] = elem;
    size++;
    return;
}

全局输出函数

注意:类模板的T和函数模板的T1不能重名

//全局函数重载
//注意:类模板的T和函数模板的T1不能重名
template <typename T1>
ostream & operator<<(ostream &out,MyArry<T1> ob){
    int i;
    for(i = 0; i<ob.size;i++){
        out<<ob.arry[i]<<endl;
    }
    return out;
}

代码实现

MyArry.hpp头文件中的代码实现

#ifndef MYARRY_HPP
#define MYARRY_HPP
#include <iostream>
#include <string.h>
using namespace std;
template <class T>
class MyArry{
    template <typename T1>
    friend ostream & operator<<(ostream &out,MyArry<T1> ob);
private:
    T *arry;  //保存数组地址
    int size; //大小
    int capacity; //容量
public:
    //无参构造
    MyArry();
    //有参构造
    MyArry(int capacity);
    //拷贝构造
    MyArry(MyArry &ob);
    //析构函数
    ~MyArry();
    //重载运算符,完成深拷贝
    MyArry & operator=(MyArry &ob);
    //插入函数
    void pushBack(T elem);
};
#endif // MYARRY_HPP

//无参构造 初始化
template<class T>
MyArry<T>::MyArry()
{
    arry = NULL;
    size = 0;
    capacity = 0;
}

//有参构造 成员变量赋值
template<class T>
MyArry<T>::MyArry(int capacity)
{
    this->capacity = capacity;
    arry = new T[this->capacity];
    size = 0;
    //清空数组
    memset(arry,0,sizeof(T)*capacity);
}

//拷贝构造
template<class T>
MyArry<T>::MyArry(MyArry &ob)
{
    //ob没有空间,拷贝的空间也没有
    if (ob.arry == NULL){
        arry = NULL;
        size = 0;
        capacity = 0;
    }
    //ob有空间,所以即将拷贝的也有空间
    else{
        capacity = ob.capacity;
        size = ob.size;
        //申请堆区数组空间
        arry = new T[capacity];
        //将旧堆区空间的值复制到新堆区空间
        memcpy(arry,ob.arry,sizeof(T)*capacity);
    }
}

//析构函数
template<class T>
MyArry<T>::~MyArry()
{
    if(arry != NULL){      //若堆区空间为空就不用析构
        delete [] arry;
    }
}

//深拷贝的时候完成赋值重载运算符  ob1 = ob2
template<class T>
MyArry<T> &MyArry<T>::operator=(MyArry &ob)
{
    //判断 this->arry是否存在空间
    if(this->arry != NULL){
       delete [] arry;
       arry = NULL;
    }
    capacity = ob.capacity;
    size = ob.size;
    //申请数组堆区空间
    arry = new T[capacity];
    //将旧堆区空间的值复制到新堆区空间
    memset(arry,0,sizeof(T)*capacity);
    //将旧堆区空间的值复制到新堆区空间
    memcpy(arry,ob.arry,sizeof(T)*capacity);
    //链式完成赋值重载运算符,返回左边运算符的引用
    return *this;
}

//输入函数
template<class T>
void MyArry<T>::pushBack(T elem)
{
    if (size == capacity){  //满
        //扩展容量
        capacity = (capacity == 0?1:2*capacity);
        //根据容量申请空间
        T *temp = new T[capacity];
        //无参构造没有给空间的代价,因为无参构造中 size == capacity
        if(arry != NULL){
            //将旧空间的内容拷贝到新空间
            memcpy(temp,arry,sizeof(T)*size);
            //释放旧空间
            delete [] arry;
        }
        arry = temp;
    }
    arry[size] = elem;
    size++;
    return;
}

//全局函数重载
//注意:类模板的T和函数模板的T1不能重名
template <typename T1>
ostream & operator<<(ostream &out,MyArry<T1> ob){
    int i;
    for(i = 0; i<ob.size;i++){
        out<<ob.arry[i]<<endl;
    }
    return out;
}


main.cpp中的测试代码实现如下

#include <iostream>
#include "myarry.hpp"
using namespace std;

int main(int argc, char *argv[])
{
   MyArry<int> ob(5);
   ob.pushBack(10);
   ob.pushBack(20);
   ob.pushBack(30);
   ob.pushBack(40);
   ob.pushBack(50);
   cout<<ob<<endl;

   cout<<"------------------------------------"<<endl;

   MyArry<char> ob1(5);
   ob1.pushBack('a');
   ob1.pushBack('b');
   ob1.pushBack('c');
   ob1.pushBack('d');
   ob1.pushBack('e');
   cout<<ob1<<endl;
   return 0;
}

代码测试结果

在main.cpp中测试自定义类型

#include <iostream>
#include "myarry.hpp"
using namespace std;

class Person{
private:
    int num;
    string name;
    int score;
public:
    Person(){};
    Person(int num,string name,int score){
        this->num = num;
        this->name = name;
        this->score = score;
    }
};

int main(int argc, char *argv[])
{
   MyArry<int> ob(5);
   ob.pushBack(10);
   ob.pushBack(20);
   ob.pushBack(30);
   ob.pushBack(40);
   ob.pushBack(50);
   cout<<ob<<endl;

   cout<<"------------------------------------"<<endl;

   MyArry<char> ob1(5);
   ob1.pushBack('a');
   ob1.pushBack('b');
   ob1.pushBack('c');
   ob1.pushBack('d');
   ob1.pushBack('e');
   cout<<ob1<<endl;

   cout<<"------------------------------------"<<endl;

   MyArry<Person> ob3;
   ob3.pushBack(Person(123,"ml",99.9));
   ob3.pushBack(Person(456,"ll",100.0));
   ob3.pushBack(Person(789,"ll",100.0));
   ob3.pushBack(Person(101,"ll",100.0));
   ob3.pushBack(Person(111,"ll",100.0));
   cout<<ob3S<<endl;
   return 0;
}

遍历出错,原因 Person 找不到输出运算符

解决方法是让 Person 重写上面的输出函数,并且要设置该函数为 Person 类的友元函数,便于访问 Person 的私有属性

#include <iostream>
#include "myarry.hpp"
using namespace std;

class Person{
    friend ostream & operator<<(ostream &out,Person ob);
private:
    int num;
    string name;
    int score;
public:
    Person(){};
    Person(int num,string name,int score){
        this->num = num;
        this->name = name;
        this->score = score;
    }
};

//设置为 Person 类的友元,便于访问 Person 的私有属性
ostream & operator<<(ostream &out,Person ob){
    out<<ob.num<<" "<<ob.name<<" "<<ob.score<<endl;
    return out;
}


int main(int argc, char *argv[])
{
   MyArry<int> ob(5);
   ob.pushBack(10);
   ob.pushBack(20);
   ob.pushBack(30);
   ob.pushBack(40);
   ob.pushBack(50);
   cout<<ob<<endl;

   cout<<"------------------------------------"<<endl;

   MyArry<char> ob1(5);
   ob1.pushBack('a');
   ob1.pushBack('b');
   ob1.pushBack('c');
   ob1.pushBack('d');
   ob1.pushBack('e');
   cout<<ob1<<endl;

   cout<<"------------------------------------"<<endl;

   MyArry<Person> ob3;
   ob3.pushBack(Person(123,"ml",99.9));
   ob3.pushBack(Person(456,"ll",100.0));
   ob3.pushBack(Person(789,"ll",100.0));
   ob3.pushBack(Person(101,"ll",100.0));
   ob3.pushBack(Person(111,"ll",100.0));
   cout<<ob3<<endl;
   return 0;
}

打印成功

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

产品运营︱用户活跃度低的解决方法

app用户活跃度低&#xff0c;产品拉新变现效率慢&#xff0c;这是运营app时难免会遇到的情况。要想解决这类问题&#xff0c;就要从可能的原因下手&#xff0c;进行产品的优化改进&#xff0c;记录下改变后的关键数据变化&#xff0c;定期做好复盘工作进行调整。 一、app用户量…

117.Android 简单的拖拽列表+防止越界拖动(BaseRecyclerViewAdapterHelper)

//1.第一步 导入依赖库和权限&#xff1a; //依赖库&#xff1a; //RecyclerView implementation com.android.support:recyclerview-v7:28.0.0//RecyclerAdapter implementation com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.28 //用到的权限&#xff1a; <!…

【华为OD机试模拟题】用 C++ 实现 - 求最大数字

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

优思学院:六西格玛管理的优势有哪些?

六西格玛的优势有哪些呢&#xff1f;以下我们来探讨一下。 一・降低企业整体成本 对企业而言&#xff0c;不良品要么被废弃&#xff0c;要么需要重新加工&#xff0c;或者需要在客户现场维修或更换&#xff0c;这些都会增加企业成本。根据美国的统计数据&#xff0c;执行3σ管…

搭建Scala集成开发环境

文章目录前言搭建Scala集成开发环境&#xff08;一&#xff09;启动IDEA&#xff08;二&#xff09;安装Scala插件&#xff08;四&#xff09;创建Scala项目1、创建Scala项目 - ScalaDemo012、创建Scala类 - HelloWorld3、创建Scala单例对象 - TestHelloWorld&#xff08;五&am…

HIVE 基础(四)

目录 分桶&#xff08;Bucket&#xff09; 设定属性 定义分桶 案例 建表语句 表数据 上传到数据 创建分桶语句 加载数据 分桶抽样&#xff08;Sampling&#xff09; 随机抽样---整行数据 随机抽样---指定列 随机抽样---百分比 随机抽样---抽取行数 Hive视图&#…

计算机基础知识——认识寄存器

下面我们就来介绍一下关于寄存器的相关内容。我们知道&#xff0c;寄存器是 CPU 内部的构造&#xff0c;它主要用于信息的存储。除此之外&#xff0c;CPU 内部还有运算器&#xff0c;负责处理数据&#xff1b;控制器控制其他组件&#xff1b;外部总线连接 CPU 和各种部件&#…

【软件测试】自动化测试的科幻大片,揭开面纱的后背......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 只要一听到 “自动化…

Solon v2.1.4 发布。支持 java、kotlin、groovy!

本次发布&#xff0c;重点测试和验证了在 java、kotlin、groovy 三种 jvm 语言里&#xff0c;开箱即用的特性。并发布 Solon Initializr&#xff1a; https://solon.noear.org/start/ &#xff08;也即将发布 idea 插件&#xff09; 最近&#xff0c;与小诺开源团队合作发布了…

JS中如何将一个普通对象转换为可迭代对象,并且可使用for...of迭代对象,内含手写一个简单的迭代器

文章目录一、认识迭代器二、为类数组添加迭代器方法三、为colorObj对象添加迭代器方法四、优化colorObj代码五、ES6内置迭代对象方法这里有一个普通对象&#xff1a; const colorObj {white: "小白",black: "小黑",gray: "小灰", }如何对 colo…

hyper-v安装koolshare软路由

注意 windows更改适配器配置&#xff0c;为hostonly适配器配置两个IP hyper-v虚拟机内存设置为2G&#xff08;windows pe启动需要&#xff09; hyper-v虚拟机配置网络》选择hostonly网络 以管理员身份运行IMG写盘工具 BIOS从IDE启动 去掉DVD驱动器 添加硬件》网络适配器》wan网…

华为机试题:HJ84 统计大写字母个数(python)

文章目录&#xff08;1&#xff09;题目描述&#xff08;2&#xff09;Python3实现&#xff08;3&#xff09;知识点详解1、input()&#xff1a;获取控制台&#xff08;任意形式&#xff09;的输入。输出均为字符串类型。1.1、input() 与 list(input()) 的区别、及其相互转换方…

10 种主数据模型设计示例分享,推荐收藏

主数据模型是主数据管理的基础&#xff0c;一个完整的、可扩展的、相对稳定的主数据模型对于主数据管理的成功起着重要的作用。规划、创建主数据模型的过程&#xff0c;是梳理主数据管理体系的过程&#xff0c;目的是建立一个良好的资源目录结构&#xff0c;划分合理的资源粒度…

网关的通用设计框架

概念 网关&#xff0c;很多地方将网关比如成门&#xff0c; 没什么问题&#xff0c; 但是需要区分网关与网桥的区别。 网桥:工作在数据链路层&#xff0c;在不同或相同类型的LAN之间存储并转发数据帧&#xff0c;必要时进行链路层上的协议转换。可连接两个或多个网络&#xf…

从0到1一步一步玩转openEuler--22 管理服务-关闭、暂停、休眠系统服务

文章目录22 管理服务-关闭、暂停、休眠系统服务22.1 systemctl命令22.2 关闭系统22.3 重启系统22.4 使系统待机22.5 使系统休眠22 管理服务-关闭、暂停、休眠系统服务 22.1 systemctl命令 systemd通过systemctl命令可以对系统进行关机、重启、休眠等一系列操作。当前仍兼容部…

WSO2 apim 多租户来区分api

WSO2 apim 多租户来区分api1. Tenant1.1 Add new tenant1.2 Add Role/User1.3 Published Api2. Delete Teant3. AwakeningWSO2安装使用的全过程详解: https://blog.csdn.net/weixin_43916074/article/details/127987099. Official Document: Managing Tenants. 1. Tenant 1.1 …

电脑常用知识与工作常用工具

什么是电脑快捷键&#xff1f; 所谓快捷键就是使用键盘上某一个或某几个键的组合完成一条功能命令&#xff0c;从而达到提高操作速度的目的。 键盘布局 主键盘区&#xff0c;数字辅助键盘区、F键功能键盘区、控制键区&#xff0c;对于多功能键盘还增添了快捷键区 一、常用快捷…

多线程Thread常用方法和状态

Thread类 及常见方法 1、常见构造方法 方法说明Thread()创建线程对象Thread(Runnable target)使用 Runnable 对象创建线程对象Thread(String name)创建线程对象&#xff0c;并命名Thread(Runnable target, String name)使用 Runnable 对象创建线程对象&#xff0c;并命名Thre…

微信银行卡如何解除绑定?图文教程,快速解除

随着移动支付的普及&#xff0c;微信支付成为人们生活中不可或缺的支付方式。在微信支付中绑定银行卡可以让用户更方便地进行支付&#xff0c;但有时候需要解除银行卡的绑定。那么&#xff0c;微信银行卡如何解除绑定呢&#xff1f;在本文中&#xff0c;小编将详细介绍微信解除…

ZooKeeper实现分布式队列、分布式锁和选举详解

提示&#xff1a;本文章非原创&#xff0c;记录一下优秀的干货。 [原创参考]&#xff1a;https://blog.csdn.net/qq_40378034/article/details/117014648 前言 ZooKeeper源码的zookeeper-recipes目录下提供了分布式队列、分布式锁和选举的实现GitHub地址。 本文主要对这几种实…