模拟实现string类——【C++】

news2024/12/29 10:12:23

W...Y的主页 😊

代码仓库分享 💕


🍔前言:

我们已经将STL中的string类重要接口全部认识并熟练掌握,为了让我们对string与C++类与对象更深层次的了解,我们这篇博客将string类进行模拟实现。

目录

 string类的模拟实现

构造函数与析构函数

拷贝构造函数

其余string类对象接口模拟实现


 string类的模拟实现

我们第一步就是区分自己模拟实现的string与STL中的string的区别,所以我们得实用命名域进行区分。然后就是私有成员的设定,string的底层就是一个数组,所以我们得创建一个字符指针,还有两个变量分别是_size检测数组中内容的大小,与_capacity检测数组的空间大小的,与顺序表的数据是相同的。

构造函数与析构函数

这两个函数是非常关键的,承载了整个string类,string的初始化与销毁都是依靠与这两个函数。

string(const char* str = "")
	:_size(strlen(str))
{
	_capacity = _size == 0 ? 4 : _size;
	_str = new char[_capacity + 1];
	strcpy(_str, str);
}

因为我们知道在STL提供的构造函数中既可以传参也可以不传参进行初始化,所以我们也使用这种初始化类型,当我们没有进行传参数时,默认创建一个空字符串。当我们传参后,我们创建的构造函数默认开辟传入字符串大小的参数,反之开辟大小为4bit的空间。如果我们选择在不传参数时不开辟空间大小,在后面的函数中会起冲突。

~string()
{
	delete[] _str;
	_str = nullptr;
	_size = _capacity = 0;
}

析构函数就非常简单,将开辟的空间进行释放,最后将_size与_capacity进行制空即可。

拷贝构造函数

针对拷贝构造函数,我们已经不能使用C++默认生成的拷贝构造函数了,因为数据类型已经不是简单的内置类型,里面有我们开辟的空间,如果使用浅拷贝就会在析构函数中释放两次相同的空间导致程序崩溃。

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

使用深拷贝使每个对象都有一份独立的资源,不要和其他对象共享 。

string(const string& s)
	:_size(s._size)
	, _capacity(s._capacity)
{
	_str = new char[s._capacity + 1];
	strcpy(_str, s._str);
}

其余string类对象接口模拟实现

 在string的模拟实现中,我们有许多类似接口可以实现,在这里我想说针对模拟实现时,我们可以使用复用已经C库中的各种函数来简单实现,并不需要进行大规模的写代码,这样可以巩固我们对函数的使用。

以下是string类函数的模拟实现完整代码:

string.h

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace why
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		typedef const char* const_iterator;
		iterator begin()const
		{
			return _str;
		}
		iterator end()const
		{
			return _str + _size;
		}
		/*string()
			:_str(new char[1])
			, _size(0)
			, _capacity(0)
		{
			_str[0] = '\0';
		}*/
		string(const char* str = "")
			:_size(strlen(str))
		{
			_capacity = _size == 0 ? 4 : _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		const char* c_str()
		{
			return _str;
		}
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}
		const char& operator[](size_t pos)const
		{
			assert(pos < _size);
			return _str[pos];
		}
		size_t size()const
		{
			return _size;
		}
		size_t capacity()const
		{
			return _capacity;
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
		//拷贝构造
		string(const string& s)
			:_size(s._size)
			, _capacity(s._capacity)
		{
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
		}
		string& operator=(const string& s)
		{
			if (this != &s)
			{
				/*delete[] _str;
				_str = new char[s._capacity + 1];
				strcpy(_str, s._str);*/
				//防止new开辟空间失败导致原数据被释放
				char* tmp = new char[s._capacity + 1];
				strcpy(tmp, s._str);
				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;

			}
			return *this;
		}
		bool operator==(const string& s)const
		{
			return strcmp(_str, s._str) == 0;
		}
		bool operator>(const string& s)const
		{
			return strcmp(_str, s._str) > 0;
		}
		bool operator<(const string& s)const
		{
			return !(*this > s || *this == s);
		}
		bool operator<=(const string& s)const
		{
			return *this == s || *this < s;
		}
		bool operator>=(const string& s)const
		{
			return *this == s || *this > s;
		}
		bool operator!=(const string& s)const
		{
			return !(*this == s);
		}
		void reserve(size_t n)
		{
			if (_capacity < n)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}
		void push_back(char ch)
		{
			if (_size + 1 > _capacity)
			{
				reserve(_capacity * 2);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}
		void append(const char* s)
		{
			size_t len = sizeof(s);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			strcpy(_str + _size, s);
			_size += len;
		}
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		string& operator+=(const char* s)
		{
			append(s);
			return *this;
		}
		void resize(size_t n, char ch = '\0')
		{
			if (n < _size)
			{
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				if (n > _capacity)
				{
					reserve(n);
				}
				size_t i = _size;
				while (i < n)
				{
					_str[i] = ch;
				}
				_size = n;
				_str[_size] = '\0';
			}
		}
		void insert(size_t pos, char x)
		{
			assert(pos <= _size);
			if (_size + 1 > _capacity)
			{
				reserve(2 * _capacity);
			}
			size_t _end = _size + 1;
			while (_end > pos)
			{
				_str[_end] = _str[_end - 1];
				_end--;
			}
			_str[pos] = x;
			_size++;
		}
		string& insert(size_t pos, const char* s)
		{
			assert(pos <= _size);
			size_t len = strlen(s);
			if (_size + len > _capacity)
			{
				reserve(_size + len );
			}
			size_t end = _size + len;
			while (end > pos + len - 1)
			{
				_str[end] = _str[end - len];
				--end;
			}
			/*size_t i = 0;
			while (i < len)
			{
				_str[pos] = s[i];
				pos++;
				i++;
			}*/
			strncpy(_str+pos, s, len);
			_size += len;
			return *this;
		}
		string& erase(size_t pos, size_t len = npos)
		{
			assert(pos < _size);

			if (len == npos || pos + len >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
			return *this;
		}
		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_capacity, s._capacity);
			std::swap(_size, s._size);
		}
		size_t find(char ch, size_t pos = 0)
		{
			assert(pos < _size);
			for (size_t i = pos; i < _size; ++i)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}
		size_t find(const char* str, size_t pos = 0)
		{
			assert(pos < _size);

			// kmp
			char* p = strstr(_str + pos, str);
			if (p == nullptr)
			{
				return npos;
			}
			else
			{
				return p - _str;
			}
		}
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		static const size_t npos;
		//static const size_t npos = -1;
	};
	const size_t string::npos = -1;
	void print(const string& s)
	{
		for (int i = 0; i < s.size(); i++)
		{
			cout << s[i] << ' ';
		}
		cout << endl;
		string::const_iterator it = s.begin();
		while (it != s.end())
		{
			cout << *it << ' ';
			++it;
		}
		cout << endl;
		for (auto ch : s)
		{
			cout << ch << ' ';
		}
		cout << endl;
	}
	
	void test1()
	{
		string s1;
		string s2("hello world");
		std::cout << s1.c_str() << std::endl;
		std::cout << s2.c_str() << std::endl;
		s2[0]++;
		std::cout << s2.c_str() << std::endl;
	}
	void test2()
	{
		string s1;
		string s2("hello world");
		string s3(s2);
		std::cout << s2.c_str() << std::endl;
		std::cout << s3.c_str() << std::endl;
		s2[0]++;
		std::cout << s2.c_str() << std::endl;
		std::cout << s3.c_str() << std::endl;
		s1 = s3;
		std::cout << s1.c_str() << std::endl;
	}
	void test3()
	{
		string s1("hello world");
		print(s1);
		string::iterator it = s1.begin();
		while (it != s1.end())
		{
			cout << *it << ' ';
			++it;
		}
		cout << endl;
		for (auto ch : s1)
		{
			cout << ch << ' ';
		}
		cout << endl;
	}
	void test4()
	{
		string s1("hello world");
		string s2("hello world");
		string s3("wwwwwww");
		cout << (s1 == s2) << endl;
		cout << (s1 != s2) << endl;
		cout << (s1 > s2) << endl;
	}
	void test5()
	{
		string s1 = "hello world";
		cout << s1.c_str() << endl;
		string s2 = "xxxxxxxxxx";
		s1.append("xxxxxxxx");
		cout << s1.c_str() << endl;
		s1 += 'c';
		s2 += "yyyyyyy";
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
		string s3;
		s3 += "ssssssss";
		cout << s3.c_str() << endl;
		string s4;
		s4 += '1';
		cout << s4.c_str() << endl;
	}
	void test6()
	{
		string s1("hello worlddddddddddddddd");
		cout << s1.capacity() << endl;
		s1.reserve(10);
		cout << s1.capacity() << endl;
	}
	void test7()
	{
		string s1;
		s1.resize(20, 'x');
		cout << s1.c_str() << endl;
		s1.resize(30, 'y');
		cout << s1.c_str() << endl;
		s1.resize(10);
		cout << s1.c_str() << endl;
	}
	void test8()
	{
		string s1("xxxxx");
		s1.insert(0, 'y');
		cout << s1.c_str() << endl;
		s1.insert(0, "wwwwww");
		cout << s1.c_str() << endl;
	}
}

test.c 

#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"

int main()
{
	//why::test1();
	//why::test2();
	//why::test3();
	//why::test4();
	//why::test5();
	//why::test7();
	why::test8();
	return 0;
}

我们在模拟实现时一定要边写边测试,从而将问题进行模块纠正,这样可以以最快的速度完成大量代码。


以上就是本次博客全部内容,感谢大家观看。

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

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

相关文章

原生微信小程序学习之旅(一) -来简单的使用

文章目录 取消导航栏标头组件创建添加Component组件接收传入的数据 页面创建(Page)关于tabBartabBar自定义样式 轮播图轮播图指示点样式改变 微信小程序快速获取用户信息路由跳转获取url路径中的参数 bindtap(click)传参wx:if编写用户登陆关于默认工程目前的获取方法尝试一下服…

海外媒体发稿:彭博社发稿宣传中,5种精准营销方式

在如今的信息发生爆炸时期&#xff0c;营销方式多种多样&#xff0c;但是充分体现精准营销并针对不同用户群体的需求并非易事。下面我们就根据彭博社发稿营销推广为例子&#xff0c;给大家介绍怎样根据不同用户人群方案策划5种精准营销方式。 1.界定总体目标用户人群在制订精准…

通过设置响应头解决跨域问题

网上很多文章都是告诉你直接Nginx添加这几个响应头信息就能解决跨域&#xff0c;当然大部分情况是能解决&#xff0c;但是我相信还是有很多情况&#xff0c;明明配置上了&#xff0c;也同样会报跨域问题。 这大概率是因为&#xff0c;服务端没有正确处理预检请求也就是OPTIONS请…

设计模式之--原型模式(深浅拷贝)

原型模式 缘起 某天&#xff0c;小明的Leader找到小明:“小明啊&#xff0c;如果有个发简历的需求&#xff0c;就是有个简历的模板&#xff0c;然后打印很多份&#xff0c;要去一份一份展示出来&#xff0c;用编程怎么实现呢&#xff1f;” 小明一听&#xff0c;脑袋里就有了…

matlab 小波自适应阈值去噪

1、内容简介 略 12-可以交流、咨询、答疑 小波自适应阈值去噪 2、内容说明 小波自适应阈值一维信号去噪&#xff0c;也包含软阈值和硬阈值 硬阈值、软阈值、自适应阈值 3、仿真分析 略 4、参考论文 略 链接&#xff1a;https://pan.baidu.com/s/1yQ1yDfk-_Qnq7tGpa23L…

【LeetCode:715. Range 模块 | 线段树】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

如何查看反汇编(VS)

如何查看反汇编 1. 设置断点2. 运行到该处3. 右键 反汇编结果 1. 设置断点 2. 运行到该处 3. 右键 反汇编 结果 即可跳转查看反汇编

kubernetes--pod详解

目录 一、pod简介&#xff1a; 1. Pod基础概念&#xff1a; 2. Kubrenetes集群中Pod的两种使用方式&#xff1a; 3. pod资源中包含的容器&#xff1a; 4. pause容器的两个核心功能&#xff1a; 5. Kubernetes中使用pause容器概念的用意&#xff1a; 二、pod的分类&#xff1a…

springboot模板引擎

1.服务端渲染时相比与前后端分离开发 原理是 跳过前端这一层 直接到服务端 通过数据和模板 生成页面返回前端 springboot包含如下模板引擎 典型如thymeleaf 1>导入依赖 2>查看路径 模板页面在 public static final String DEFAULT_PREFIX “classpath:/templates/”; 即…

便捷Benchmark.sh 自动匹配workload(自用)

​ 因为db_bench选项太多&#xff0c;而测试纬度很难做到统一&#xff08;可能一个memtable大小的配置都会导致测试出来的写性能相关的的数据差异很大&#xff09;&#xff0c;所以官方给出了一个benchmark.sh脚本用来对各个workload进行测试。 该脚本能够将db_bench测试结果中…

华为ensp:开启rstp修改根网桥

开启rstp 首先去三台交换机上进入系统视图分别开启rstp模式 stp mode rstp 三台交换机上都执行这个命令&#xff0c;就开启rstp模式了 修改根网桥 现在进入要被修改的交换机的系统视图 stp priority 4096 这里我们修改只要比别的交换机数值小就可以&#xff0c;最小的就是…

(二)正点原子I.MX6ULL u-boot移植

一、概述 这里使用的是NXP官方2022.04发布的uboot&#xff0c;移植到正点原子阿尔法开发板&#xff08;v2.1&#xff09; u-boot下载&#xff1a;gitgithub.com:nxp-imx/uboot-imx.git 移植是基于NXP的mx6ull_14x14_evk 二、编译NXP官方uboot 进入NXP的u-boot目录 先在Makefile…

linux 下非sudo安装cmake

1.查看位数 getconf LONG_BIT2.下载对应压缩包 Download CMake Source Distribution 未编译源代码 Binary Distribution已经编译好的 3.解压至文件夹 tar -zxvf cmake-3.28.0-rc4-linux-x86_64.tar.gz 4.添加环境变量 vi ~/.bashrc 最后一行添加 写到bin目录 export P…

深度解析NLP定义、应用与PyTorch实战

1. 概述 文本摘要是自然语言处理&#xff08;NLP&#xff09;的一个重要分支&#xff0c;其核心目的是提取文本中的关键信息&#xff0c;生成简短、凝练的内容摘要。这不仅有助于用户快速获取信息&#xff0c;还能有效地组织和归纳大量的文本数据。 1.1 什么是文本摘要&#x…

从HDFS到对象存储,抛弃Hadoop,数据湖才能重获新生?

Hadoop与数据湖的关系 1、Hadoop时代的落幕2、Databricks和Snowflake做对了什么3、Hadoop与对象存储&#xff08;OSD&#xff09;4、Databricks与Snowflake为什么选择对象存储5、对象存储面临的挑战 1、Hadoop时代的落幕 十几年前&#xff0c;Hadoop是解决大规模数据分析的“白…

大数据治理运营整体解决方案:PPT全文39页,附下载

关键词&#xff1a;大数据&#xff0c;数据治理&#xff0c;数据治理解决方案&#xff0c;数据治理的目的和意义 一、数据治理的定义 数据治理专注于将数据作为企事业单位数据资产进行应用和管理的一套管理机制&#xff0c;能够消除数据的不一致性&#xff0c;建立规范的数据应…

【算法】算法题-20231110

一、力口&#xff1a;506. 相对名次 简单 给你一个长度为 n 的整数数组 score &#xff0c;其中 score[i] 是第 i 位运动员在比赛中的得分。所有得分都 互不相同 。 运动员将根据得分 决定名次 &#xff0c;其中名次第 1 的运动员得分最高&#xff0c;名次第 2 的运动员得分第…

【ARM入门】ARM、SOC、ARM授权 概念篇

什么是ARM ARM前身是Acorn公司设计的第一款微处理器&#xff0c;叫ARM&#xff1a;Acorn RISC Machine ARM公司的名字叫ARM&#xff1a;Advanced RISC Machines ARM内核 包括了寄存器组、指令集、总线、存储器映射规则、中断逻辑和调试组件等 内核是有ARM公司设计并以销售方…

HarmonyOS 高级特性

引言 本章将探讨 HarmonyOS 的高级特性&#xff0c;包括分布式能力、安全机制和性能优化。这些特性可以帮助你构建更强大、更安全、更高效的应用。 目录 HarmonyOS 的分布式能力HarmonyOS 的安全机制HarmonyOS 的性能优化总结 1. HarmonyOS 的分布式能力 HarmonyOS 的分布…

视频批量剪辑:视频嵌套合并实战指南,剪辑高手速成秘籍

随着社交媒体的兴起&#xff0c;视频制作的需求越来越广泛。无论是个人用户还是专业团队&#xff0c;都需要对视频进行剪辑以符合其需求。而在这个过程中&#xff0c;批量剪辑视频的能力就变得至关重要。视频批量剪辑是指在一次操作中处理多个视频文件的剪辑。通过使用专业的视…