C++ 一个有关类模板、构造函数、析构函数、拷贝构造、重载等的数组案例分析

文章目录

    • 概要
    • 根据代码和输出进行分析(看注释和图示)
    • 个人小结

概要

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

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

根据代码和输出进行分析(看注释和图示)

MyArray.hpp代码:

#pragma once
#include<iostream>
using namespace std;


template<class T>
class MyArray
{
public:
    //有参构造 参数 容量
    MyArray(int capacity)
    {   
        cout << "MyArray的有参构造调用" << endl;
        this->m_Capacity = capacity; // 期望所存
        this->m_Size = 0; //现存
        this->pAddress = new T[this->m_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];
        //将arr中的数据都拷贝过来
        for (int i = 0; i < this->m_Size; i++)
        {   
            // 如果T为对象,而且还包含指针,必须需要重载 = 操作符,因为这个等号不是 构造 而是赋值,
			// 普通类型可以直接= 但是指针类型需要深拷贝
            this->pAddress[i] = arr.pAddress[i];
        }
    }

    //operator= 防止浅拷贝问题  a=b=c 自带的=能实现链式编程
    MyArray& operator=(const MyArray& arr)
    {   
        cout << "MyArray的operator=赋值运算符重载调用" << 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_Capacity; i++){
            this->pAddress[i] = arr.pAddress[i];
        }
        
        return *this; //MyArray& = *this
    }

    //尾插法
    void Push_Back(const T & val){
        //判断容量是否等于大小
        if (this->m_Capacity == this->m_Size){
            return;
        }
        this->pAddress[this->m_Size] = val;
        this->m_Size++;
    }

    //尾删法
    void Pop_Back(){
        //让用户访问不到最后一个元素,即为尾删(逻辑上的删除方式)
        if (this->m_Size == 0){
            return;
        }
        this->m_Size--;
    }

    //让用户通过下标方式访问数组中的元素
    //重载[],因为数据类型是我们自己定义的
    T& operator[] (int index){ //arr[0] = 100 为了让它可以做左值,需要返回T的引用  这种思想也是链式编程思想

        return this->pAddress[index];
    }

    //返回数组容量
    int getCapacity(){
        return this->m_Capacity;
    }
    //返回数组大小
    int getSize(){
        return this->m_Size;
    }
    
    //析构函数
    ~MyArray()
    {   
        cout << "MyArray的析构函数调用" << endl;
        if(this->pAddress != nullptr){
            delete [] this->pAddress; //指向的是数组
            this->pAddress = nullptr; //指针置空,防止野指针
        }
    }

private:
    T * pAddress;

    int m_Capacity;

    int m_Size;


};

Main.cpp代码

#include <iostream>
#include "MyArray.hpp"
#include <windows.h>//用于函数SetConsoleOutputCP(65001);更改cmd编码为utf8
#include <string>
using namespace std;

void PrintIntArray(MyArray<int> arr) //会调用拷贝构造函数,如果写成MyArray<int> &arr就不会调用了!
{
    for (int i =0; i < arr.getSize(); i++){
        cout << arr[i] << endl;
    }
}

//测试内置数据类型
void test01(){
    MyArray<int> arr1(5); //有参构造  数据放在栈上
    
    for (int i = 0; i < 5; i++){
        arr1.Push_Back(i); // 尾插法
    }
    cout << "arr1的打印输出:" << endl;
    PrintIntArray(arr1);

    cout << "arr1的容量:" << arr1.getCapacity() << endl;
    cout << "arr1的大小:" << arr1.getSize() << endl;

    MyArray<int>arr2(arr1);//拷贝构造
    cout << "arr2的打印输出:" << endl;
    PrintIntArray(arr2);

    //尾删
    arr2.Pop_Back();
    cout << "arr2尾删后:" << endl;
    cout << "arr2的容量:" << arr2.getCapacity() << endl;
    cout << "arr2的大小:" << arr2.getSize() << endl;

	MyArray<int>arr3(100); //有参构造
    arr3 = arr1; //等号赋值

}

int main(){

    SetConsoleOutputCP(65001);

    test01();

    cout <<"执行完毕" <<endl;
    system("pause");

    return 0;
}

输出与解释:
在这里插入图片描述
我有个点不太确定,请大佬指正是否正确:因为arr1 2 3是创建在栈上的局部变量,所以遵循先进后出的原则释放,所以先释放arr3,然后依次释放arr2、arr1。

个人小结

上面这个案例很好的总结了C++有关类和函数的相关核心知识,获益匪浅。

花了两个多星期,黑马的课程终于看到STL模板库了,后面继续学习加油吧(ง •_•)ง

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT-编译报库错误(LF/CRLF)

QT-安装后环境问题记录 版本和环境问题 版本和环境 QT5.15.2 Windows10 QT Creator 问题 在QT夸端开发的项目中 &#xff0c;使用QTCreator打开项目pro文件&#xff0c;编译报出很多系统库 及本地文件中的一些问题&#xff0c;具体如图&#xff1a; 后续&#xff0c;我以为…

【b站李同学的Lee】Part 2 模块化开发 NodeJS+Gulp基础入门+实战

课程地址&#xff1a;【NodeJSGulp基础入门实战】 https://www.bilibili.com/video/BV1aE411n737/?share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 目录 4 Node.js模块化开发 4.1 JavaScript开发弊端 4.1.1 文件依赖 4.1.2 命名冲突 4.2 生活中的…

Midjourney常见玩法及prompt关键词技巧

今天系统给大家讲讲Midjourney的常见玩法和prompt关键词的一些注意事项&#xff0c;带大家入门&#xff5e;&#xff08;多图预警&#xff0c;建议收藏&#xff5e;&#xff09; 一、入门及常见玩法 1、注册并添加服务器&#xff08;会的童鞋可跳过&#xff5e;&#xff09; …

DC-9渗透测试复现

DC-9渗透测试复现 目的&#xff1a; 获取最高权限以及flag 过程&#xff1a; 信息打点--sql注入- 文件包含漏洞-Knockd开门开启ssh连接-hyjra爆破-sudo提权(文件追加) 环境&#xff1a; 攻击机&#xff1a;kali(192.168.85.137) 靶机&#xff1a;DC_3(192.168.85.141) …

GPT状态和原理 - 解密OpenAI模型训练

目录 1 如何训练 GPT 助手 1.1 第一阶段 Pretraining 预训练 1.2 第二阶段&#xff1a;Supervised Finetuning有监督微调 1.3 第三阶段 Reward Modeling 奖励建模 1.4 第四阶段 Reinforcement Learning 强化学习 1.5 总结 2 第二部分&#xff1a;如何有效的应用在您的应…

【Linux】Linux信号

目录 信号的概念 生活中的信号 Linux中的信号 kill命令 kill 命令的使用 常见的信号 命令行代码示例 注意事项 信号的处理方式 产生信号 信号的捕捉 信号捕捉示意图 内核如何实现信号捕捉 信号的捕捉与处理 小结 阻塞信号 信号在内核中的表示图 信号集操作函数…

如何学习嵌入式Linux?

如何去学习嵌入式 Linux 呢&#xff1f;嵌入式底层开发毫无疑问是一项极为关键重要的技术&#xff0c;其被广泛地应用于形形色色的嵌入式系统之中。伴随科技的迅猛飞速发展&#xff0c;嵌入式系统已然成为了我们生活中不可或缺的一个组成部分&#xff0c;这也极为凸显出了嵌入式…

基于 Bazel 的 iOS Monorepo 工程实践

在之前很长一段时间里&#xff0c;哔哩哔哩 iOS 工程是使用 Polyrepo&#xff08;或者说 Multirepo&#xff0c;即多仓库&#xff09;的传统模式进行开发。但是随着业务的发展&#xff0c;我们的代码仓库的数量也随之膨胀&#xff0c;我们慢慢发现 Polyrepo 模式并不一定是适合…

DDoS攻击愈演愈烈,谈如何做好DDoS防御

DDoS攻击是目前最常见的网络攻击方式之一&#xff0c;各种规模的企业包括组织机构都在受其影响。对于未受保护的企业来讲&#xff0c;每次DDoS攻击的平均成本为20万美元。可见&#xff0c;我们显然需要开展更多的DDoS防御工作。除考虑如何规避已发生的攻击外&#xff0c;更重要…

手机副业赚钱秘籍:让你的手机变成赚钱利器

当今社会&#xff0c;智能手机已然成为我们生活不可或缺的一部分。随着技术的飞速进步&#xff0c;手机不再仅仅是通讯工具&#xff0c;而是化身为生活伴侣与工作助手。在这个信息爆炸的时代&#xff0c;我们时常会被一种焦虑感所困扰&#xff1a;如何能让手机超越消磨时光的定…

关于Git的一些基础用法

关于Git的一些基础用法 1. 前言2. 使用GitHub/gitee创建项目2.1 创建账号2.2 创建项目2.3 下载仓库到本地2.4 提交代码到远端仓库2.5 查看日志2.6 同步远端仓库和本地仓库 1. 前言 首先说一个冷知识&#xff08;好像也不是很冷&#xff09;&#xff0c;Linux和git的创始人是同…

CC254X 8051芯片手册介绍

1 8051CPU 8051是一种8位元的单芯片微控制器&#xff0c;属于MCS-51单芯片的一种&#xff0c;由英特尔(Intel)公司于1981年制造。Intel公司将MCS51的核心技术授权给了很多其它公司&#xff0c;所以有很多公司在做以8051为核心的单片机&#xff0c;如Atmel、飞利浦、深联华等公…

C++:类型转换

目录 1、C语言中的类型转换 2、C的四种类型转换 2.1 static_cast 2.2 reinterpret_cast 2.3 const_cast 2.4 dynamic_cast 3 RTTI 1、C语言中的类型转换 如果 赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者返回值类型与 接收返回值…

TexStudio + MikTex 手动安装宏包

遇到上面这个 “宏包安装” 提示窗口后&#xff0c;设置来源为本地&#xff0c;随后在这个网址 https://mirrors.ustc.edu.cn/CTAN/systems/win32/miktex/tm/packages/ 下载所需的宏包&#xff0c;放到本地仓库里&#xff0c;即可 有三个宏包是必须要有的&#xff0c;它们是索…

上下文输入无限制,谷歌发布Infini-Transformer

去年&#xff0c;百川智能发布号称全球最长的上下文窗口大模型Baichuan2-192K&#xff0c;一次性可输入35万字&#xff0c;超越GPT-4。 今年3月&#xff0c;Kimi智能助手宣布在上下文窗口技术上突破200万字。 紧追其后&#xff0c;国内各大互联网巨头纷纷布局升级自家大模型产…

JAVA基础08- 继承,重写,super以及this

目录 继承&#xff08;extends&#xff09; 定义 说明 作用 方法的重写 定义 重写关键点 方法重写与重载的区别 练习 练习1&#xff08;方法继承与重写的简单练习&#xff09; 练习2&#xff08;方法继承与重写的进阶练习&#xff09; This的使用 定义 作用以及注…

Postman之版本信息查看

Postman之版本信息查看 一、为何需要查看版本信息&#xff1f;二、查看Postman的版本信息的步骤 一、为何需要查看版本信息&#xff1f; 不同的版本之间可能存在功能和界面的差异。 二、查看Postman的版本信息的步骤 1、打开 Postman 2、打开设置项 点击页面右上角的 “Set…

MyBatis 源码分析 - SQL 的执行过程

MyBatis 源码分析 - SQL 的执行过程 * 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程。该过程本身比较复杂&#xff0c;牵涉到的技术点比较多。包括但不限于 Mapper 接口代理类的生成、接口方法的解析、SQL 语句的解析、运行时参数的绑定、查询结果自动映射、延…

基于SpringBoot+Vue的二手车交易系统的设计与实现(源码+文档+包运行)

一.系统概述 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统二手车交易信息管理难度大&#xff0c;容错率低&…

Connection: keep-alive 简介

一、在使用fiddler抓包工具会出现如下场景 二、keep-alive 保持连接 "Connection: keep-alive" 是 HTTP 协议中的一个头部字段&#xff0c;用于指示客户端和服务器之间的连接是否保持活跃状态。 当客户端发送一个 HTTP 请求给服务器时&#xff0c;可以在请求头部中包…