C++——基础复习——模拟动态数组容器

一、功能

1、尾插

2、随机插入

3、随机访问

4、随机查找

5、删除指定下标元素

6、删除指定元素

7、字符串输出

二、功能基类

复习知识:

1、虚函数:实现动态多态,通过派生类的重写实现扩展功能;提高代码的复用性;提高实例化对象的灵活性,使用基类指针或引用指向派生类对象,无需严格控制实例化类型。派生类中可用override标记重写虚函数,使代码更加规范。

2、纯虚函数:实现动态多态的关键;在基类中不提供函数体,直接=0;在派生类中重写纯虚函数,提供统一功能函数接口;

3、抽象类:含有纯虚函数的类叫做抽象类,无法实例化对象;派生类中需要全部重写基类中的纯虚函数,否则也是抽象类。

4、纯虚析构函数:需要类外实现。

5、模板:使用模板功能定义一个基类,接收任何类型的参数;定义一个全局变量作为错误返回值。

#pragma once
/****************************************
*			可变大小容器实现			*
*			基本功能:增、查、删、改	*
*			1、数组实现					*
*			2、链表实现					*
*****************************************/
template<typename T>
T ERROR;
//可变容器功能函数基类模板,提供统一接口
template<typename T>
class MutableContainerFunc {
public://在末位添加元素virtual void add(const T& element) = 0;//在指定下标添加元素virtual void add(const T& element, int index) = 0;//通过下标查找元素virtual T& getEle(int index) = 0;//通过元素查找下标virtual int getIndex(const T& element) = 0;//通过下标删除元素,返回删除元素值virtual T remove(int index) = 0;//通过元素删除元素,返回删除元素值virtual T removeEle(const T& element) = 0;//通过下标修改元素virtual void set(int index, const T& element) = 0;//升序排序virtual void sort() = 0;//转换为字符串virtual string str() = 0;//纯虚析构函数virtual ~MutableContainerFunc() = 0;
};
template<typename T>
MutableContainerFunc<T>::~MutableContainerFunc() {}

三、数组实现

复习知识点:

1、重载:为了解决传入指针参数是指针类型的情况,重载了部分特化函数处理指针;重载了数组运算符[]

2、排序:冒泡排序和插入排序

3、字符串流:包含stringstream头文件,可用ostringstream类构造字符串流,用istringstream类读取字符串流。

#pragma once
#include"MutableContainerFunc.hpp"
#include<iostream>
#include<sstream>
using namespace std;template<typename T>
class MutableContainerArray :public MutableContainer<T>
{
private:T* Con_ptr;size_t Con_len;
public:MutableContainerArray();MutableContainerArray(int len);~MutableContainerArray() override;//在末位添加元素void add(const T& element) override;void add(const T* ptr) override;//在指定下标添加元素void add(const T& element, int index) override;void add(const T* ptr, int index) override;//通过下标查找元素T& getEle(int index) override;//通过元素查找下标int getIndex(const T& element) override;int getIndex(const T* ptr) override;//通过下标删除元素,返回删除元素值T remove(int index) override;//通过元素删除元素,返回删除元素值T removeEle(const T& element) override;T removeEle(const T* ptr) override;//通过下标修改元素void set(int index, const T& element) override;void set(int index, const T* ptr) override;//升序排序void sort() override;//转换为字符串string str() override;//数组符号重载T& operator[](int index) override;
};template<typename T>
inline MutableContainerArray<T>::MutableContainerArray()
{this->Con_len = 0;this->Con_ptr = NULL;
}template<typename T>
inline MutableContainerArray<T>::MutableContainerArray(int len)
{this->Con_len = len;this->Con_ptr = new T[Con_len];
}template<typename T>
inline MutableContainerArray<T>::~MutableContainerArray()
{if (this->Con_ptr) {delete this->Con_ptr;this->Con_ptr = NULL;this->Con_len = 0;}
}template<typename T>
inline void MutableContainerArray<T>::add(const T & element)
{T* temp = new T[Con_len + 1];for (int i = 0; i < Con_len; i++) {temp[i] = Con_ptr[i];}temp[this->Con_len++] = element;delete this->Con_ptr;this->Con_ptr = temp;
}template<typename T>
inline void MutableContainerArray<T>::add(const T * ptr)
{add(*ptr);
}template<typename T>
inline void MutableContainerArray<T>::add(const T & element, int index)
{if (index >= 0 && index <= this->Con_len) {T* temp = new T[++this->Con_len];for (int i = 0, j = 0; i < this->Con_len; i++) {if (i == index) {continue;}temp[i] = this->Con_ptr[j++];}temp[index] = element;delete this->Con_ptr;this->Con_ptr = temp;}
}template<typename T>
inline void MutableContainerArray<T>::add(const T * ptr, int index)
{add(*ptr, index);
}template<typename T>
inline T& MutableContainerArray<T>::getEle(int index)
{return this->Con_ptr[index];
}template<typename T>
inline int MutableContainerArray<T>::getIndex(const T & element)
{int res = -1;for (int i = 0; i < this->Con_len; i++) {if (this->Con_ptr[i] == element) {res = i;break;}}return res;
}template<typename T>
inline int MutableContainerArray<T>::getIndex(const T * ptr)
{return getIndex(*ptr);
}template<typename T>
inline T MutableContainerArray<T>::remove(int index)
{T res = ERROR<T>;if (index >= 0 && index < this->Con_len) {res = this->Con_ptr[index];T* temp = new T[this->Con_len - 1];for (int i = 0, j = 0; i < this->Con_len; i++) {if (i == index) {continue;}temp[j++] = this->Con_ptr[i];}delete this->Con_ptr;this->Con_ptr = temp;this->Con_len--;}return res;
}template<typename T>
inline T MutableContainerArray<T>::removeEle(const T & element)
{T res = ERROR<T>;int index = getIndex(element);if (index != -1) {res = element;remove(index);}return res;
}template<typename T>
inline T MutableContainerArray<T>::removeEle(const T * ptr)
{return removeEle(*ptr);
}template<typename T>
inline void MutableContainerArray<T>::set(int index, const T & element)
{if (index >= 0 && index <= this->Con_len) {this->Con_ptr[index] = element;}
}template<typename T>
inline void MutableContainerArray<T>::set(int index, const T * ptr)
{return set(index, *ptr);
}template<typename T>
inline void MutableContainerArray<T>::sort()
{for (int i = 0; i < this->Con_len - 1; i++) {int minindex = i;for (int j = i + 1; j < this->Con_len; j++) {if (this->Con_ptr[j] < this->Con_ptr[minindex]) {minindex = j;}}if (minindex != i) {T temp = this->Con_ptr[minindex];this->Con_ptr[minindex] = this->Con_ptr[i];this->Con_ptr[i] = temp;}}//for (int i = 0; i < Con_len; i++) {//	for (int j = 0; j < Con_len - 1 - i; j++) {//		if (Con_ptr[j + 1] < Con_ptr[j]) {//			T temp = Con_ptr[j];//			Con_ptr[j] = Con_ptr[j + 1];//			Con_ptr[j + 1] = temp;//		}//	}//}
}
template<typename T>
inline string MutableContainerArray<T>::str()
{ostringstream oss;oss << "[";if (this->Con_len) {for (int i = 0; i < this->Con_len - 1; i++) {oss << this->Con_ptr[i] << ",";}oss << this->Con_ptr[this->Con_len - 1];}oss << "]";return oss.str();
}template<typename T>
inline T & MutableContainerArray<T>::operator[](int index)
{return Con_ptr[index];
}

四、链表实现

复习知识点:

1、大小:size_t 和int ,一般表示数组大小用size_t,防止溢出或者不同平台出现不兼容

2、初始化列表构造:initializer_list<T>   也就是{a,b,c,d…};

#pragma once
#include<iostream>
using namespace std;
#include<sstream>
//声明节点类
template<typename T>
class Node {
public:T N_value;Node<T>* pre;Node<T>* next;Node();Node(const T& value);Node(const T* ptr);
};//声明链表
template<typename T>
class MutableContainerList :public MutableContainer<T> {
public://链表头、尾指针Node<T>* Con_begin;Node<T>* Con_end;//链表长度size_t Con_len;//构造、析构函数MutableContainerList();MutableContainerList(initializer_list<T> initlist);~MutableContainerList()override;//在末位添加元素void add(const T& element) override;void add(const T* ptr) override;//在指定下标添加元素void add(const T& element, int index) override;void add(const T* ptr, int index) override;//通过下标查找元素T& getEle(int index) override;//通过元素查找下标int getIndex(const T& element) override;int getIndex(const T* ptr) override;//通过下标删除元素,返回删除元素值T remove(int index) override;//通过元素删除元素,返回删除元素值T removeEle(const T& element) override;T removeEle(const T* ptr) override;//通过下标修改元素void set(int index, const T& element) override;void set(int index, const T* ptr) override;//升序排序void sort() override;//转换为字符串string str() override;//数组符号重载T& operator[](int index);//通过下标获得节点指针Node<T>* getPtr(int index);
};template<typename T>
inline Node<T>::Node()
{pre = next = nullptr;
}template<typename T>
inline Node<T>::Node(const T & value)
{N_value = value;pre = next = nullptr;
}template<typename T>
inline Node<T>::Node(const T * ptr)
{Node(*ptr);
}template<typename T>
inline MutableContainerList<T>::MutableContainerList()
{Con_begin = Con_end = nullptr;Con_len = 0;
}template<typename T>
inline MutableContainerList<T>::MutableContainerList(initializer_list<T> initlist)
{Con_len = 0;Con_begin = Con_end = nullptr;for (const T& value : initlist) {add(value);}
}template<typename T>
inline MutableContainerList<T>::~MutableContainerList()
{while (Con_begin) {Node<T>* temp = Con_begin->next;delete Con_begin;Con_begin = temp;}
}template<typename T>
inline void MutableContainerList<T>::add(const T & element)
{Node<T>* temp = new Node<T>(element);if (!Con_len) {Con_begin = Con_end = temp;}else {temp->pre = Con_end;Con_end->next = temp;Con_end = temp;}Con_len++;
}template<typename T>
inline void MutableContainerList<T>::add(const T * ptr)
{add(*ptr);
}template<typename T>
inline void MutableContainerList<T>::add(const T & element, int index)
{Node<T>* temp = getPtr(index);if (temp) {Node<T> *node = new Node<T>(element);temp->pre->next = node;node->pre = temp->pre;node->next = temp;temp->pre = node;Con_len++;}
}template<typename T>
inline void MutableContainerList<T>::add(const T * ptr, int index)
{add(*ptr, index);
}template<typename T>
inline T & MutableContainerList<T>::getEle(int index)
{return (*this)[index];
}template<typename T>
inline int MutableContainerList<T>::getIndex(const T & element)
{Node<T>* temp = Con_begin;int i = 0;for (i = 0; temp->N_value != element && i < Con_len; i++, temp = temp->next);return i < Con_len ? i : -1;
}template<typename T>
inline int MutableContainerList<T>::getIndex(const T * ptr)
{return getIndex(*ptr);
}template<typename T>
inline T MutableContainerList<T>::remove(int index)
{Node<T>* temptr = getPtr(index);T res = temptr->N_value;temptr->pre->next = temptr->next;temptr->next->pre = temptr->pre;delete temptr;Con_len--;return res;
}template<typename T>
inline T MutableContainerList<T>::removeEle(const T & element)
{return remove(getIndex(element));
}template<typename T>
inline T MutableContainerList<T>::removeEle(const T * ptr)
{return removeEle(*ptr);
}template<typename T>
inline void MutableContainerList<T>::set(int index, const T & element)
{(*this)[index] = element;
}template<typename T>
inline void MutableContainerList<T>::set(int index, const T * ptr)
{set(index, *ptr);
}template<typename T>
inline void MutableContainerList<T>::sort()
{for (int i = 0; i < Con_len - 1; i++) {for (int j = 0; j < Con_len - 1 - i; j++) {T& valuej = (*this)[j];T& valuej1 = (*this)[j + 1];if (valuej > valuej1) {T temp = valuej;valuej = valuej1;valuej1 = temp;}}}
}template<typename T>
inline string MutableContainerList<T>::str()
{ostringstream oss;oss << "[";for (Node<T>* temp = Con_begin; temp->next; temp = temp->next) {oss << temp->N_value << ",";}oss << Con_end->N_value << "]";return oss.str();
}template<typename T>
inline T & MutableContainerList<T>::operator[](int index)
{Node<T>* temp = Con_begin;if (index >= 0 && index < Con_len) {for (int i = 0; i < index; i++, temp = temp->next);return temp->N_value;}else {return ERROR<T>;}}template<typename T>
inline Node<T>* MutableContainerList<T>::getPtr(int index)
{Node<T>* temp = nullptr;if (index >= 0 && index < Con_len) {temp = Con_begin;for (int i = 0; temp&&i < Con_len; i++, temp = temp->next);}return temp;
}

五、我要认真了

小一:背景

写代码的时候我钻进了死胡同,分开解释。

第一种情况:T是基础类型或者自定义基础类型,在数组和链表析构时,不需要特殊处理。

第二种情况:T本身是指针类型,而且指向堆区空间,在数组和链表析构时,如果不释放掉就会造成内存泄漏。

小二:那么问题来了:

众所周知(装一下,其实我也是刚知道),C++是一种静态类型的编程语言,所有类型在编译阶段就已经确定,那么我们的模板中,该如何判断传入的参数是什么类型呢?

小三:感谢文心一言:

抓破脑袋想不出办法的时候,文心一言靠谱了一回。他说条件编译和类型萃取(不明觉厉),然后我就恶补一下。enable_if 和 is_pointer 登场。

1、类型萃取:编译阶段判断类型,主要通过模板实现,提前优化或者排错。头文件<type_traits>,看源码是一个一路继承下来的类模板,T是指针时继承了true_type,返回1;T不是指针时,继承了false_type,返回0;在<type_traits>文件中还有多种模板,判断类型例如:

is_class<T> :判断是否是自定义类型

is_reference<T>:判断是否为引用

is_integral<T>:判断是否为整形

…………等等

//判断是否为指针类型,返回bool值
is_pointer<T>::value

2、条件编译:C++的条件编译主要依赖于预处理器指令,这些指令在编译过程的预处理阶段被处理。常见的条件编译指令包括#if#ifdef#ifndef#elif#else#endif等。而enable_if是实现类模板内成员函数条件编译的一个模板类,他通过对一个布尔条件的判断确定是否返回类型补齐模板,条件为true返回指定类型,补齐模板,通过编译;当条件为false,则不返回任何东西,模板实例化失败,跳过后续的类模板或者函数模板的编译。

template<typename = typename enable_if<true,void>::type>;

代码中第一个typename 是用来声明模板参数的。它告诉编译器接下来的名字,此处是匿名;

代码中第二个typename 用来告诉编译器,enable_if<…>::type 是一个类型

它通过在函数模板的参数列表中添加一个额外的模板参数,并结合类型萃取技术,实现对函数模板的条件编译。源码如下:

template<bool _Test,class _Ty = void>struct enable_if{	// type is undefined for assumed !_Test};template<class _Ty>struct enable_if<true, _Ty>{	// type is _Ty for _Testusing type = _Ty;};template<bool _Test,class _Ty = void>using enable_if_t = typename enable_if<_Test, _Ty>::type;

小四:那么问题是否解决了呢?

并没有, 当我试图使用条件编译来编写针对指针数据特化版本的成员函数时发现,函数模板实例化是在编译时进行的,而虚函数是在运行时绑定的。意思也就是:虚函数不能是函数模板。那么与其让多态和继承让步于条件编译,不如不用条件编译。

而且:重点是,我一直想把数据中内存维护的任务加到容器中,其实是强“容”所难了,容器做好自身的内存维护就好,至于数据所指向的内存,应该由数据本身或者操作者去维护。所以,将模拟容器中对指针数据的特化版成员函数中的指针表示为:T*,从而实现特化,程序也就更加清晰。事实上,模板元编程中也是这么处理的。例如:

//指针类型判断
template<class T>struct is_pointer<T*>:true_type{};

小结:程序设计要保持清晰的条理性,遵循客观规律。 

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

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

相关文章

Maven 之 配置文件pom

<?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://…

代码随想录阅读笔记-哈希表【赎金信】

题目 给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串&#xff0c;判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成&#xff0c;返回 true &#xff1b;否则返回 false。 (题目说明&#xff1a;为了不暴露赎金信字迹&#x…

Rabbit MQ详解

写在前面,由于Rabbit MQ涉及的内容较多&#xff0c;赶在春招我个人先按照我认为重要的内容进行一定总结&#xff0c;也算是个学习笔记吧。主要参考官方文档、其他优秀文章、大模型问答。自己边学习边总结。后面有时间我会慢慢把所有内容补全&#xff0c;分享出来也是希望可以给…

CSS学习(1)-选择器

一、基本选择器 1. 通配选择器 作用&#xff1a;可以选中所有的 HTML 元素。 语法&#xff1a; * { 属性名: 属性值; }举例&#xff1a; /* 选中所有元素 */ * { color: orange; font-size: 40px; }主要用于&#xff1a;清除样式。 2. 元素选择器 作用&#xff1a;为页面…

QT5.14.2 探索Qt字符串操作的奥秘:Qt的QString如何成为你的编程利器?

在Qt的世界里&#xff0c;字符串处理是一项基础而关键的技能。无论是从用户输入中提取数据&#xff0c;还是对数据进行格式化输出&#xff0c;掌握QString的使用都能显著提升你的开发效率。本文将带你深入探索QString&#xff0c;看看QString如何成为你的编程利器&#xff01; …

如何引入ElementUI组件库,快速上手Element

前言&#xff1a;在上篇文章中分享了如何快速上手Vue框架项目&#xff0c;本篇文章则介绍的是Element的使用&#xff0c;通过本篇文章的分享&#xff0c;我们就可以将Vue和Element结合使用&#xff0c;快速构建出精美的网页界面 目录 一.Element和ElementUI 二.如何引入Eleme…

leetcod 685. 冗余连接 II

久违的没做太出来的题目&#xff0c;leetcod 685. 冗余连接 II 题目 在本问题中&#xff0c;有根树指满足以下条件的 有向 图。该树只有一个根节点&#xff0c;所有其他节点都是该根节点的后继。该树除了根节点之外的每一个节点都有且只有一个父节点&#xff0c;而根节点没有…

关于Oracle Primavera P6的各数据库帐号用途

在使用/维护P6时&#xff0c;经常会用到各种不同的P6数据库用户&#xff0c;如在连接配置P6 Professional时用到的公共帐号pubuser&#xff0c;进入后台维护p6配置信息(adminpv)或开发常连接的privuser&#xff0c;亦或是配置BI Report/BUSINESS Intelligence报表套件用到的pxr…

OpenAI Q-Star:AGI距离自我意识越来越近

最近硅谷曝出一份54页的内部文件&#xff0c;揭露了去年OpenAI宫斗&#xff0c;导致Altman&#xff08;奥特曼&#xff09;差点离职的神秘项目——Q-Star&#xff08;神秘代号Q*&#xff09;。 根据该文件显示&#xff0c;Q-Star多模态大模型拥有125万亿个参数&#xff0c;比现…

ARM架构中导致独占式内存访问Exclusive access 指令(LDXR/STXR)失败的原因分析

在之前的博文当中&#xff0c;笔者介绍了ARM中支持同步和信号量的硬件实现机制&#xff1a;Exclusive access&#xff08;独占式访问&#xff09;以及Load-Exclusive/Store-Exclusive指令的使用&#xff1a; ARMv8 同步和信号量&#xff08;Synchronization and semaphores&…

什么是ping

[Q&A] ping的作用 探测本机与网络里另一主机是否已建立连接&#xff0c;常用语检测网络是否畅通&#xff0c;获取连接速度等信息。 [Q&A] ping的原理 ping命令的原理基于ICMP&#xff08;Internet Control Message Protocol&#xff09;协议&#xff0c;这是一种网络…

7.Java整合MongoDB—项目创建

整合MongoDB MongoDB的基本知识有所了解之后&#xff0c;我们开始着手上代码了&#xff0c;进来先来项目创建&#xff0c;如何引入mongodb&#xff0c;以及测试一下能否连接数据库。 1 新建springboot项目 其实只需要spring boot mongodb这个依赖就行&#xff0c;加那么多纯属…

Kubernetes kafka系列 | k8s部署kafka+zookeepe集群

一、kafka.zookeeper介绍 Kafka 简介&#xff1a; Apache Kafka 是一个开源的分布式流处理平台和消息队列系统。它最初由LinkedIn开发&#xff0c;并于2011年成为Apache软件基金会的顶级项目。 特点&#xff1a; 高吞吐量&#xff1a; Kafka 能够处理大规模的消息流&#xf…

【TB作品】MSP430,波形发生器,单片机,Proteus仿真

文章目录 题目效果梯形波100个点产生方法锯齿波100个点产生方法c代码和proteus仿真 题目 114 波形发生器的制作 设计要求 设计一个能产生正弦波、方波、三角波、梯形波、锯齿波的波形发生器。设置5个开关K1~K5(从 上到下),分别对应正弦波、方波、三角波、梯形波、锯齿波,按一下…

短剧分销怎么赚钱的?保姆级教程助你短剧cps推广赚大钱

短剧分销怎么赚钱的&#xff1f;小白也能月入过万/“蜂小推“保姆级教程&#xff0c;助你短剧分销赚大钱&#xff01; 相信大家或多或少都在某些群里看到一些“霸道总裁爱上职场小菜鸟...”“这类链接&#xff0c;无利不起早&#xff0c;为什么会有那么多在群里分享这些狗血视…

习题11-2 查找星期

本题要求实现函数&#xff0c;可以根据下表查找到星期&#xff0c;返回对应的序号。 序号星期0Sunday1Monday2Tuesday3Wednesday4Thursday5Friday6Saturday 函数接口定义&#xff1a; int getindex( char *s ); 函数getindex应返回字符串s序号。如果传入的参数s不是一个代表…

Pycharm连接远程服务器Anoconda中的虚拟环境

在配置远程解释器时&#xff0c;踩过一些坑&#xff0c;现在记录一下配置过程&#xff1a; 步骤1&#xff1a; 打开pycharm的File里面的Settings 里面的Project:你的项目名称目录下的Python Interpreter。 步骤二&#xff1a; 点击右上角的“add interpreter”&#xff0c;选择…

String为什么要设计成不可变的

String被设计成不可变的主要有以下几个原因&#xff1a; 线程安全&#xff1a;不可变的String对象可以被多个线程安全地共享&#xff0c;因为它们的值是在创建时确定的&#xff0c;不会改变。这样就避免了多线程环境下的并发访问和修改带来的竞争问题。 缓存哈希值&#xff1a…

美光领跑HBM3e赛道,率先获得NVIDIA H200 AI GPU订单

据韩国《中央日报》的一篇报道&#xff0c;在美光于2024年2月启动最新高带宽内存HBM3e的大规模生产后&#xff0c;近日已成功获得NVIDIA为其H200 AI GPU的订单。据悉&#xff0c;NVIDIA即将推出的H200处理器将会搭载最新的HBM3e&#xff0c;性能超越了H100处理器所使用的HBM3。…

Tomcat内存马

Tomcat内存马 前言 描述Servlet3.0后允许动态注册组件 这一技术的实现有赖于官方对Servlet3.0的升级&#xff0c;Servlet在3.0版本之后能够支持动态注册组件。 而Tomcat直到7.x才支持Servlet3.0&#xff0c;因此通过动态添加恶意组件注入内存马的方式适合Tomcat7.x及以上。…