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

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.mfbz.cn/a/135461.html

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

相关文章

【C++】C++入门详解 I【C++入门 这一篇文章就够了】

C入门 前言一、C关键字&#xff08;C98&#xff09;二、命名空间 namespace&#xff08;一&#xff09;namespace的出现&#xff08;二&#xff09;namespace的定义&#xff08;1&#xff09;namespace 的正常定义&#xff08;2&#xff09;namespace的功能特性1. 命名空间 可嵌…

SharePoint 的 Web Parts 是什么

Web Parts 可以说是微软 SharePoint 的基础组件。 根据微软自己的描述&#xff0c;Web Parts 是 SharePoint 对内容进行构建的基础&#xff0c;可以想想成一块一块的砖块。 我们需要使用这些砖块来完成一个页面的构建。 我们可以利用 Web Parts 在 SharePoint 中添加文本&am…

时序预测 | MATLAB实现基于BP-Adaboost的BP神经网络结合AdaBoost时间序列预测

时序预测 | MATLAB实现基于BP-Adaboost的BP神经网络结合AdaBoost时间序列预测 目录 时序预测 | MATLAB实现基于BP-Adaboost的BP神经网络结合AdaBoost时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于BP-Adaboost的BP神经网络结合AdaB…

NZ系列工具NZ08:图表添加标签工具

我的教程一共九套及VBA汉英手册一部&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到数据库&#xff0c;到字典&#xff0c;到高级的网抓及类的应用。大家在学习的过程中可能会存在困惑&#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…

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

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

Word 插入的 Visio 图片显示为{EMBED Visio.Drawing.11} 解决方案

World中&#xff0c;如果我们插入了Visio图还用了Endnote&#xff0c; 就可能出现&#xff1a;{EMBED Visio.Drawing.11}问题 解决方案&#xff1a; 1.在相应的文字上右击&#xff0c;在出现的快捷菜单中单击“切换域代码”&#xff0c;一个一个的修复。 2.在菜单工具–>…

配置交换机将Log发送到日志服务器

文章目录 一、配置说明二、配置步骤推荐阅读 一、配置说明 配置将实现如下&#xff1a; 配置交换机将Log发送到日志服务器。 将信息等级高于等于 debug 的日志信息将会发送到日志服务器上。 允许输出日志信息的模块为default所有应用模块日志信息。 SW1为我们日志源交换机…

【Redis】redis的下载安装

目录 1.window安装 2.Linux安装 下载 解压 移动redis目录 编译 1.window安装 在github 下载redis的安装包 https://github.com/microsoftarchive/redis/releases 下载完后安装相应的目录下&#xff0c;比如我是放在c盘的Program Files下 开启redis&#xff0c;双击运行…

CCF ChinaSoft 2023 论坛巡礼|程序设计教育论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

SQL练习---511.游戏玩法分析 I

题目描述 分析 题目描述很简单&#xff0c;找出用户第一次登陆的时期&#xff0c;很简单一个用户有多个记录&#xff0c;因此按用户分组即可&#xff0c;但是不知道日期能否求出最小值&#xff0c;事实证明还是可以的。 题解 select player_id,min(event_date) first_login f…

Linux的命令——关于操作用户及用户组的命令

目录 1.Linux的命令格式 2.用户与用户组管理 2.1用户管理 添加用户 设置用户密码 删除用户 修改用户 2.2用户组管理 新增用户组 删除用户组 修改用户组属性 用户组切换 用户组管理 用户切换 1. su 2.sudo 1.Linux的命令格式 Linux系统中几乎所有操作&#xff0…

基于STM32控制直流电机加减速正反转仿真设计

**单片机设计介绍&#xff0c;基于STM32控制直流电机加减速正反转仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 本设计由STM32F103、L298N电机驱动电路、按键电路组成。通过按键可以控制电机&#xff0c;正转、反转、加…

8年经验之谈 —— 接口测试框架中的鉴权处理!

接口自动化测试中通常都有鉴权机制&#xff0c;就是判断是否在登录状态下&#xff0c;已登录方可调用接口&#xff0c;未登录则不可调用。本文将带领大家学习使用rest-assured框架实现基于cookies和token的鉴权关联&#xff0c;实现接口自动化测试。 1、基于cookies的鉴权关联…

Http状态码502常见原因及排错思路(实战)

Http状态码502常见原因及排错思路 502表示Bad Gateway。当Nginx返回502错误时&#xff0c;通常表示Nginx作为代理服务器无法从上游服务器&#xff08;如&#xff1a;我们的后端服务器地址&#xff09;获取有效的响应。导致这种情况的原因有很多&#xff1a; 后端服务器故障ngin…

基于SpringBoot+Vue的博物馆管理系统

基于springbootvue的博物馆信息管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 登录界面 管理员界面 用户界面 摘要 基于SpringBoot和Vue的博物馆…

vue3响应式api

响应式api——compositon api setup&#xff1a; 不要再想this问题执行是在beforeCreated之前 beforeCreated&#xff1a;也就是创建了一个实例 created&#xff1a;挂载了数据 通过形参props接收&#xff0c;只读 以后所有代码都写到setup中 判断是否只读&#xff1a;isReadon…

lc228. 汇总区间

暴力解法&#xff1a;遍历数组&#xff0c;判断数组是否连续递增。将连续递增的数据的首尾的数据分别存储在map集合的key和value之中&#xff0c;输出时判断首尾值是否相同采用两种方式输出 复杂度分析 时间复杂度&#xff1a;O(n)&#xff0c;其中 n 为数组的长度。空间复杂…

2023亚太杯数学建模A题思路

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料5 最后 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 2023年第十三…

【LeetCode】每日一题 2023_11_12 每日一题 Range 模块

文章目录 刷题前唠嗑题目&#xff1a;Range 模块题目描述代码与解题思路 刷题前唠嗑 LeetCode? 启动&#xff01;&#xff01;&#xff01; 嗯&#xff1f;怎么是 hard&#xff0c;好长&#xff0c;可恶&#xff0c;看不懂&#xff0c;怎么办 题目&#xff1a;Range 模块 题…