【035】C++泛型编程(模板)实践:设计数组类模板模仿vector容器

news2024/11/16 19:46:20

C++泛型编程(模板)实践

  • 引言
  • 一、类模板的概述
  • 二、实现数组类模板
  • 三、类模板的继承
    • 3.1、类模板派生出普通类
    • 3.2、类模板派生出类模板
  • 总结

引言


💡 作者简介:专注于C/C++高性能程序设计和开发,理论与代码实践结合,让世界没有难学的技术。包括C/C++、Linux、MySQL、Redis、TCP/IP、协程、网络编程等。
👉
🎖️ CSDN实力新星,社区专家博主
👉
🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
👉
🔔 专栏地址:C++从零开始到精通
👉
🔔 博客主页:https://blog.csdn.net/Long_xu


🔔 上一篇:【034】C++泛型编程(模板)之 类模板详解(最全讲解)

一、类模板的概述

C++ 类模板是一种用于创建通用类的机制,它可以让程序员编写一次类,然后让它适用于多种类型,在实际编程中非常实用。

类模板和函数模板的定义和使用类似。有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,类模板用于实现类所需数据的类型参数化。

类模板的定义方式类似于普通类的定义,只是需要在类名后面添加一对尖括号,其中包含类型参数列表。

设计一个数组类模板,可以存放任意数据类型。

二、实现数组类模板

类模板一般在hpp文件里面实现。由于数组类模板要存放任何数据类型,所以先定义一个模板类型T。
Data.hpp

#pragma once
#ifndef _DATA_H_
#include <string.h>
#include <iostream>
using namespace std;

// 类模板
template <class T>
class MyArray {
	template<class T1>
	friend ostream& operator<<(ostream &out, MyArray<T1> ob);
private:
	T *arr;//数组首地址
	int size;//实际大小
	int capacity;//总容量大小。
public:
	MyArray();
	MyArray(int capacity);
	MyArray(const MyArray &ob);
	~MyArray();
	MyArray& operator=(MyArray &ob);
	void pushBack(T elem);//插入元素
	void sortArrary();//排序
	

};


#endif // !_DATA_H_

template<class T>
MyArray<T>::MyArray()
{
	capacity = 5;
	size = 0;
	arr = new T[capacity];
	memset(arr, 0, sizeof(T)*capacity);
}

template<class T>
MyArray<T>::MyArray(int capacity)
{
	this->capacity = capacity;
	size = 0;
	arr = new T[capacity];
	memset(arr, 0, sizeof(T)*capacity);
}

template<class T>
MyArray<T>::MyArray(const MyArray & ob)
{
	this->capacity = ob.capacity;
	this->size = ob.size;
	this->arr = new T[this->capacity];
	memset(this->arr, 0, sizeof(T)*this->capacity);

	memcpy(this->arr, ob.arr, sizeof(T)*this->capacity);
}

template<class T>
MyArray<T>::~MyArray()
{
	if (arr != NULL)
	{
		delete[] arr;
		arr = NULL;
	}
}

template<class T>
MyArray<T> & MyArray<T>::operator=(MyArray<T> & ob)
{
	// 判断 this->arr是否存在空间
	if (arr != NULL)
	{
		delete[] arr;
		arr = NULL;
	}
	// TODO: 在此处插入 return 语句
	this->capacity = ob.capacity;
	this->size = ob.size;
	this->arr = new T[this->capacity];
	memset(this->arr, 0, sizeof(T)*this->capacity);

	memcpy(this->arr, ob.arr, sizeof(T)*this->capacity);
	return *this;
}

template<class T>
void MyArray<T>::pushBack(T elem)
{
	// 判断容器是否满
	if (size == capacity)
	{
		// 扩容
		capacity = 2 * capacity;
		// 申请临时空间
		T *tmp = new T[capacity];
		if (arr != NULL)
		{
			// 将旧空间数据拷贝到新空间
			memcpy(tmp, arr, sizeof(T)*size);
			// 释放旧空间
			delete[] arr;

		}
		// arr指向新空间
		arr = tmp;
	}
	arr[size] = elem;
	size++;
}

template<class T>
void MyArray<T>::sortArrary()
{
	if (size == 0)
	{
		cout << "容器没有数据" << endl;
		return;
	}
	// 冒泡排序
	for (int i = 0; i < size - 1; i++)
	{
		for (int j = 0; j < size - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				T tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

template<class T1>
ostream& operator<<(ostream &out, MyArray<T1> ob)
{
	for (int i = 0; i < ob.size; i++)
	{
		out << ob.arr[i] << " ";
	}
	out << endl;
	return out;
}

main.cpp

#include <iostream>
#include <string>
using namespace std;

class Person {
	// 重载<<运算符
	friend ostream& operator<<(ostream &out, Person ob);
private:
	int num;
	string name;
	float score;
public:
	// 必须要有无参构造
	Person(){

	}
	Person(int num, string name, float score)
	{
		this->num = num;
		this->name = name;
		this->score = score;
	}
	// 重载>运算符才能正确比较
	bool operator>(Person &ob)
	{
		return num > ob.num;
	}
};

ostream& operator<<(ostream &out,Person ob)
{
	out << ob.num << " " << ob.name << " " << ob.score << endl;
	return out;
}

#include "Data.hpp"
int main()
{
	// 类模板实例化对象
	MyArray<int> arr01;
	arr01.pushBack(20);
	arr01.pushBack(60);
	arr01.pushBack(40);
	cout << arr01 << endl;
	arr01.sortArrary();
	cout << arr01 << endl;


	MyArray<char> arr02;
	arr02.pushBack('A');
	arr02.pushBack('H');
	arr02.pushBack('D');
	cout << arr02 << endl;
	arr02.sortArrary();
	cout << arr02 << endl;

	// 对象的存储
	MyArray<Person> person;
	person.pushBack(Person(102,"hello",92.30f));
	person.pushBack(Person(108, "world", 95.30f));
	person.pushBack(Person(103, "lests", 98.30f));
	person.sortArrary();
	cout << person << endl;

	return 0;
}

三、类模板的继承

3.1、类模板派生出普通类

在类模板派生处具体化为普通类。

示例:

#include <iostream>
using namespace std;

template<class T1,class T2>
class Base {
private:
	T1 a;
	T2 b;
public:
	Base() {}
	Base(T1 a, T2 b);
	void showData();
};

template<class T1, class T2>
Base<T1, T2>::Base(T1 a, T2 b)
{
	this->a = a;
	this->b = b;
}

template<class T1, class T2>
void Base<T1, T2>::showData()
{
	cout << a << " " << b << endl;
}

// 在类模板派生处具体化为普通类
class Son :public Base<int, char> {
public:
	int c;
public:
	Son(int a, char b, int c) :Base<int, char>(a, b) {
		this->c = c;
	}
};

int main()
{
	Son ob(100, 'A', 200);
	ob.showData();
	return 0;
}

3.2、类模板派生出类模板

抽象化类型。

示例:

#include <iostream>
using namespace std;

template<class T1,class T2>
class Base {
private:
	T1 a;
	T2 b;
public:
	Base() {}
	Base(T1 a, T2 b);
	void showData();
};

template<class T1, class T2>
Base<T1, T2>::Base(T1 a, T2 b)
{
	this->a = a;
	this->b = b;
}

template<class T1, class T2>
void Base<T1, T2>::showData()
{
	cout << a << " " << b << endl;
}

// 在类模板派生类模板
template<class T1, class T2class T3>
class Son :public Base<T1, T2> {
public:
	T3 c;
public:
	Son(T1 a, T2 b, T3 c) :Base<T1, T2>(a, b) {
		this->c = c;
	}
};

int main()
{
	Son ob(100, 'A', 200);
	ob.showData();
	return 0;
}

总结

C++ 的标准库中提供了 std::vector 容器,它是一个动态数组,能够在运行时根据需要动态调整大小。如果想要实现一个类似于 std::vector 的容器,需要考虑以下几个要点:

  1. 动态内存管理:类似于 std::vector,你需要使用动态内存分配来管理存储元素的内存。可以使用 newdelete 或者 mallocfree 等来实现。

  2. 大小和容量管理:你的容器应该具有类似于 std::vectorsize()capacity() 方法,用于获取当前存储元素的数量和容器的容量。当容量不足时,需要进行内存重新分配来扩大容量。

  3. 元素访问和操作:你的容器应该提供类似于 std::vectorpush_back()pop_back()at()front()back() 等方法来访问和操作容器中的元素。还需要实现类似于 std::vector 的迭代器来遍历容器。

  4. 内存管理和异常安全:你需要确保容器在内存管理和异常安全方面与 std::vector 一致。例如,在内存重新分配时,需要正确地处理内存释放和重新分配,以及在发生异常时确保容器的状态不会被破坏。

  5. 复制和移动语义:你的容器应该具有正确的复制和移动语义,包括拷贝构造函数、拷贝赋值运算符、移动构造函数和移动赋值运算符等。

  6. 内存回收:当容器不再需要时,需要正确地释放内存,避免内存泄漏。可以在容器的析构函数中进行内存释放。

总结起来,实现一个类似于 std::vector 的容器需要考虑动态内存管理、大小和容量管理、元素访问和操作、内存管理和异常安全、复制和移动语义以及内存回收等方面。这涉及到动态内存分配、指针和引用、构造函数和析构函数、运算符重载等 C++ 的一些基本概念和技术。在实际编程中,可以参考 std::vector 的实现和相关的 C++ 标准库文档来更深入地了解和实现类似的容器。

在这里插入图片描述

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

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

相关文章

[MySQL]MySQL表的约束

[MySQL]表的约束 文章目录 [MySQL]表的约束1. 约束的概念2. 空属性(null/not null)3. 默认值(default)4. 列描述(comment)5. 填充零(zerofill)6. 主键(primary key)7. 自增长(auto_increment)8. 唯一键(unique)9. 外键(foreign key) 1. 约束的概念 数据库通过技术手段限制数据的…

ping是什么,有什么作用?

什么是Ping Ping是一种计算机网络管理员软件实用程序&#xff0c;通常用于检查主机的可访问性。可访问性包括两个方面。一个是可用性&#xff0c;另一个是响应时间。 ping 请求可以通过大多数命令行界面中标准的 ping 命令执行。Ping是什么意思&#xff1f;它是一个实用程序&…

同步锁-线程安全问题解决方案

同步锁-线程安全问题解决方案 目录 同步锁-线程安全问题解决方案1 同步锁1.1 前言1.2 同步与异步1.3 synchronized同步关键字1.3.1 写法1.3.2 前提1.3.3 特点1.4.1练习-改造售票案例implements Runnable1.4.2 练习-改造售票案例extends Thread 1.5 之前遇到过的同步例子 2 线程…

IIC(硬件实现)-GD32

IIC&#xff08;硬件实现&#xff09;-GD32 #include "i2c.h"void i2c_init(void){i2c_deinit(I2C0);//使能外设时钟rcu_periph_clock_enable(RCU_I2C0);rcu_periph_clock_enable(RCU_GPIOB);//设置gpio口gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO…

SSM项目 shiro整合redis

一、准备阶段&#x1f349; 创建好web工程后&#xff08;不会创建的可以看我前几篇文章&#xff09; 看不懂的小伙伴可以看一下我的第一篇文章里面有详细的介绍 1.引入依赖&#x1f95d; <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"ht…

数据库管理-第九十期 本周升级一小坑(20230709)

第九十期 本周升级一小坑 19c OCM依然在准备之中&#xff0c;第三堂和第四堂应该在下周内完成。 本周割接了3次&#xff0c;一次给X8M计算节点换内存&#xff08;可修复的ECC报错了&#xff0c;没影响生产&#xff09;&#xff0c;两次都是给X8那套升级&#xff08;就是多灾多…

基础IO及文件系统

一、系统接口介绍 1. open()命令 模式下&#xff1a;ctrlv进入visual block模式&#xff0c;然后选择J、K&#xff0c;然后输入大写i&#xff0c;然后输入//&#xff0c;最后按ESC&#xff0c;即可完成批量注释&#xff0c;按u取消。ctrl v 进入块选择模式&#xff0c;选中你要…

LinuxCP插件virtio与内核vhost

以下为LCP创建的接口对&#xff0c;VPP侧为物理接口port7&#xff0c;映射到Linux侧的为虚拟接口hostap1&#xff0c;接口hostap1作为vhost的后端存在。VPP侧接口tap1为前端的virtio接口。 vpp# show lcp itf-pair: [0] port7 tap1 hostap1 24 type tap vdp# vdp# show interf…

QT登录界面

1.效果图 2.代码 #include "widget.h" #include "ui_widget.h" #include <QApplication> #include <QWidget> #include <QtWidgets>Widget::Widget(QWidget *parent): QMainWindow(parent), ui(new Ui::Widget) {ui->setupUi(this);…

【数据结构二叉树OJ系列】5、相同的树和另一个树

目录 一、相同的树 二、另一个树的子树 一、相同的树 题述&#xff1a; 给定二叉树&#xff0c;检验他们是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为他们是相同的。 示例1&#xff1a; 题中已给&#xff1a; struct TreeNode {i…

黑马大数据学习笔记0-环境配置

目录 设置VMware网络CentOS操作系统三台虚拟机系统配置&#xff1a;主机名、固定IP、SSH免密登录配置主机名映射配置SSH免密登录创建hadoop用户并配置免密登录JDK1.8环境部署防火墙、SELinux、时间同步设置快照 视频p3-p5 https://www.bilibili.com/video/BV1WY4y197g7?p3 设…

tomcat第1章 tomcat介绍、安装、部署项目

一、前言 我们在写javaweb程序的时候有没有考虑如果没有tomcat&#xff0c;我们怎么给客户端返回响应数据&#xff1f;既然能返回响应数据&#xff0c;为什么还要使用tomcat&#xff1f; 什么是tomcat&#xff0c;以及tomcat历史版本发展情况&#xff0c;每个版本servlet规范…

如何与ChatGPT愉快地聊天

原文链接&#xff1a;https://mp.weixin.qq.com/s/ui-O4CnT_W51_zqW4krtcQ 人工智能的发展已经走到了一个新的阶段&#xff0c;在这个阶段&#xff0c;人工智能可以像人一样与我们进行深度的文本交互。其中&#xff0c;OpenAI的ChatGPT是一个具有代表性的模型。然而&#xff0…

JavaFX学习:MVC模式中的PropertyValueFactory

PropertyValueFactory类是“TableColumn cell value factory”,绑定创建列表中的项。示例如下&#xff1a; TableColumn<Person,String> firstNameCol new TableColumn<Person,String>("First Name");firstNameCol.setCellValueFactory(new PropertyVal…

Blender基础入门(3):复杂建模技巧

文章目录 我个人的Blender专栏前言基础属性设置选择循环选择&#xff1a;Alt左键透视选择锁定物体编辑模式123快捷键按下/&#xff08;右侧Shift左边&#xff0c;<>按键右边&#xff09;&#xff0c;锁定物体先在物体模式选择物体&#xff0c;再到编辑模式就只会选择该物…

淘宝订单拉取更新历史状态~需求

&#x1f4da;目录 订单接口api需求问题解决 Map<String,TaobaoOrder> 订单接口api 可自行查询官网文档&#xff0c;点击进入 需求 通过接口中has_next 标识判断该时间断是否还有下一页数据,直到该值数据为false时,表面该时间范围内的订单数据获取完成. 拉取完成后需要对…

Maven工程开发中的继承与聚合

1. 聚合工程概念 设置一个空的maven工程&#xff0c;工程里面只有pom文件&#xff0c;另外将这个工程的打包方式设置为pom。 在聚合工程里面添加聚合工程里面管理的模块 2.聚合总结 3.继承 例如下面02工程继承上面的01工程&#xff0c;在02工程的pom文件中要配置要继承的父工…

分组统计--Pandas

1.groupby 1.1 函数功能 先对数据进行分组&#xff0c;然后在每个分组上运用聚合函数、转换函数 1.2 函数语法 DataFrame.groupby(byNone, axis0, levelNone, as_indexTrue, sortTrue, group_keysTrue, observedFalse, dropnaTrue)1.3 函数参数 参数含义by分组依据axis沿着…

【电子学会】2023年05月图形化一级 -- 找食物

找食物 1. 准备工作 &#xff08;1&#xff09;添加背景&#xff1a;Jungle&#xff1b; &#xff08;2&#xff09;删除小猫角色&#xff0c;添加角色&#xff1a;Dog2、Donut&#xff1b; 2. 功能实现 &#xff08;1&#xff09;点击绿旗&#xff0c;小狗的初始位置在舞…

打家劫舍(力扣)动态规划 JAVA

你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个房屋存放金额的非…