【C++】模式实现string

本文展示了如何模拟实现C++中的string类,包括构造函数、拷贝构造函数、迭代器、内存管理(如reserve、resize)以及字符串的基本操作(如push_back、append、insert、erase)。同时,提供了测试代码以验证各个功能的正确性。
摘要由CSDN通过智能技术生成

上期我们详细讲解了string,本期为了更深入理解string,我们自己手动实现一下string类。

话不多说,下面是模拟string的源码以及测试代码(关于代码的详细讲解都标在注释中了哦):

string.h  (模拟实现string代码):

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include <cassert>
#include <ostream>
namespace lhs
{
	class string
	{
	public:
		//模拟实现迭代器
		typedef char* iterator;//正向迭代器
		typedef const char* const_iterator;//常量正向迭代器
		iterator begin()
		{
			return _str;//返回字符串首元素的地址
		}
		iterator end()
		{
			return _str + _size;//返回字符串最后一个元素后一个位置的地址
		}
		const_iterator begin()const
		{
			return _str;//返回字符串首元素的地址
		}
		const_iterator end()const
		{
			return _str + _size;//返回字符串最后一个元素后一个位置的地址
		}
		//构造函数
		string(const char* str = "")//这里缺省值给空串,默认为"\0"。使用const来修饰是为了方便解决传入常量字符串类型不匹配的问题
			:_size(strlen(str))
		{
			_capacity = _size;
			_str = new char[_capacity + 1];//_capaicty + 1是为了统计字符串最后的"\0"
			strcpy(_str, str);//拷贝传入的字符串至string类的动态开辟的空间中
		}
		//拷贝构造函数
		string(const string& s)
			:_size(s._size)
			,_capacity(s._capacity)
		{
			_str = new char[_capacity + 1];//_capaicty + 1是为了预留字符串最后的"\0"位置
			strcpy(_str, s._str);//拷贝传入string类的字符串至新的string类的动态开辟的空间中
		}
		//size函数接口
		size_t size()const
		{
			return _size;
		}
		//capacity函数接口
		size_t capacity()const
		{
			return _capacity;
		}
		//c_str函数接口
		const char* c_str()const
		{
			return _str;
		}
		//reserve接口
		void reserve(size_t n)
		{
			if (n > _capacity)//保证空间不会缩容
			{
				char* temp = new char[n + 1];//n + 1是为了预留字符串最后的"\0"位置,这里使用临时变量来接收,防止开辟空间失败
				strcpy(temp, _str);//拷贝数据
				delete[] _str;//释放旧空间
				_str = temp;//重新指向新空间
				_capacity = n;
			}
		}
		//resize函数接口
		void resize(size_t n, const char ch = '\0')
		{
			if (n <= _size)//删除多余数据
			{
				_str[n] = '\0';
				_size = n;
			}
			else//size外剩余数据初始化
			{
				if (n > _capacity)//判断是否需要扩容
				{
					reserve(n);
				}
				//初始化数据
				for (size_t i = _size; i < _capacity; ++i)
				{
					_str[i] = ch;
				}
				_str[_capacity] = '\0';
				_size = n;
			}
		}
		//push_back接口
		void push_back(const char ch)
		{

			if (_size + 1 > _capacity)//判断字符串容量是否足够
			{
				if (_capacity == 0)//对于字符串容量为0的情况特殊对待
				{
					reserve(2);//扩容
				}
				else
				{
					reserve(_size * 2);//扩容
				}
			}
			_str[_size] = ch;//追加字符
			++_size;
			_str[_size] = '\0';//追加完字符后别忘了添上'\0'哦
		}
		//append接口
		void append(const char* str)
		{
			size_t n = strlen(str);
			if (_size + n > _capacity)//判断字符串容量是否足够
			{
				reserve(_size + n);//扩容
			}
			strcpy(_str + _size, str);//追加字符串
			_size += n;

		}
		//insert函数接口
		string& insert(size_t pos, const char ch)
		{
			assert(pos <= _size);
			if (_size + 1 > _capacity)//判断字符串容量是否足够
			{
				reserve(2 * _capacity);
			}
			//移动数据
			size_t begin = _size;
			while (begin > pos) 
			{
				_str[begin] = _str[begin - 1];
				--begin;
			}
			//插入字符
			_str[pos] = ch;
			++_size;
			_str[_size] = '\0';//插入完字符后别忘了添上'\0'哦
			return *this;
		}
		string& insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (_size + len > _capacity)//判断字符串容量是否足够
			{
				reserve(_size + len);
			}
			//移动数据,在这个移动过程中字符串的'\0'一起移动了
			size_t begin = _size + len;
			while (begin >= pos + len)
			{
				_str[begin] = _str[begin - len];
				--begin;
			}
			//插入字符串
			for (size_t i = pos, n = 0; i < pos + len; ++i, ++n)
			{
				_str[i] = str[n];
			}
			_size += len;
			return *this;
		}
		//erase函数接口
		string& erase(size_t pos, size_t len = npos)
		{
			assert(pos <= _size);
			if (len == npos || len + pos > _size)//删除pos后所有数据
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else//删除pos后len个数据
			{
				//移动数据
				for (size_t i = pos; i <= _size - len; ++i)
				{
					_str[i] = _str[i + len];
				}
				_size -= len;
			}
			return *this;
		}
		//swap函数接口
		void swap(string& s)
		{
			//临时变量储存数据
			size_t Tsize = s._size, Tcapacity = s._capacity;
			char* Tstr = s._str;
			//交换数据
			s._size= _size;
			s._capacity= _capacity;
			s._str= _str;
			_size = Tsize;
			_capacity = Tcapacity;
			_str = Tstr;
		}
		//find函数接口
		size_t find(const 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);
			//暴力查找字符串
			size_t len = strlen(str);
			for (size_t i = pos; i < _size; ++i)
			{
				size_t j = 0;
				for (; j < len; ++j)
				{
					if (i + len > _size)
						break;
					if (_str[i + j] != str[j])
						break;
				}
				if (j == len)
					return i;
			}
			return npos;
		}
		//clean函数接口
		void clean()
		{
			_str[0] = '\0';
			_size = 0;
		}
		//运算符重载
		char& operator[](size_t pos)//可修改引用
		{
			assert(pos < _size);
			return _str[pos];
		}
		const char& operator[](size_t pos)const//不可修改常量引用
		{
			assert(pos < _size);
			return _str[pos];
		}
		string& operator=(const string& s)
		{
			if (this != &s)//防止自身对自身进行赋值
			{
				_size = s._size;
				_capacity = s._capacity;
				char* temp = new char[_capacity + 1];//这里使用临时变量来接收,防止开辟空间失败
				delete[] _str;//释放旧空间
				_str = temp;//重新指向新空间
				strcpy(_str, s._str);
			}
			return *this;
		}
		bool operator>(const string& s)const
		{
			size_t min = s._size > _size ? _size : s._size;
			//一个个按字符的ASCLL码进行比较
			size_t i = 0;
			for (; i < min; ++i)
			{
				if (_str[i] > s._str[i])
					return true;
			}
			if (i == s._size && s._size != _size)
				return true;
			else
				return false;
		}
		bool operator==(const string& s)const
		{
			if (s._size != _size)
				return false;
			//一个个按字符的ASCLL码进行比较
			for (size_t i = 0; i < _size; ++i)
			{
				if (_str[i] != s._str[i])
					return false;
			}
			return true;
		}
		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);
		}
		string& operator+=(const char ch)
		{
			push_back(ch);
			return *this;
		}
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
		//析构函数
		~string()
		{
			delete[] _str;
		}
	private:
		size_t _size;//有效字符数
		size_t _capacity;//容量大小
		char* _str;//有效数据
		static const size_t npos;
	};
	const size_t string::npos = -1;

	//流插入
	std::ostream & operator<<(std::ostream & out,const string& s)
	{
		for (auto ch: s)
		{
			std::cout << ch;
		}
		std::cout << std::endl;
		return out;
	}
	//流提取
	std::istream& operator>>(std::istream& in, string& s)
	{
		s.clean();
		char ch = in.get();//为了拿到键盘输入的所有字符这里用到了in.get函数,普通的流提取>>会将空格和换行字符流入到缓冲区中
		char buff[188];//为了防止输入的字符串过长,导致string的频繁扩容,这里使用一个字符数组来缓冲,将数组填满后再存入string的字符串中
		size_t i = 0;
		while (ch!='\n')//一直一个一个拿键盘中输入的字符,直到遇到换行符
		{
			if (i == 187)//数组存满后,将数组中的数据插入到string中,防止频繁扩容
			{
				buff[187] = '\0';
				s += buff;
				i = 0;
			}
			buff[i++] = ch;//将拿到的字符插入到数组中
			ch = in.get();//继续拿下一个字符
		}
		if (i != 0)//将数组未存入string的数据存入string
		{
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}
}

StringTest.cpp  (测试代码):

#include"string.h"
void Test1()
{
	lhs::string s1;
	lhs::string s2("Hello world");
	std::cout << s1.c_str() << std::endl;
	std::cout << s2.c_str() << std::endl;
	++s2[8];
	std::cout << s2.c_str() << std::endl;
}
void Test2()
{
	lhs::string s1="Hello world";
	lhs::string s2(s1);
	std::cout << s1.c_str() << std::endl;
	std::cout << s2.c_str() << std::endl;
	++s1[4];
	++s2[9];
	std::cout << s1.c_str() << std::endl;
	std::cout << s2.c_str() << std::endl;
}
void Test3()
{
	lhs::string s1 = "Hello world";
	lhs::string s2 = s1;
	std::cout << s1.c_str() << std::endl;
	std::cout << s2.c_str() << std::endl;
	++s1[4];
	++s2[9];
	std::cout << s1.c_str() << std::endl;
	std::cout << s2.c_str() << std::endl;
	s2 = s2;
	std::cout << s2.c_str() << std::endl;
}
void Print(const lhs::string& s)
{
	for (size_t i = 0; i < s.size(); ++i)
	{
		std::cout << s[i];
	}
	std::cout << std::endl;
	for (auto ch : s)//自己实现了迭代器,范围for就可以自动识别了
	{
		std::cout << ch;
	}
	std::cout << std::endl;
}
void Test4()
{
	lhs::string s1 = "Hello world";
	std::cout << s1.c_str() << std::endl;
	Print(s1);
}
void Test5()
{
	lhs::string s1 = "Hello world";
	lhs::string::iterator it = s1.begin();
	while (it != s1.end())
	{
		std::cout << *it;
		++it;
	}
	std::cout << std::endl;
	it = s1.begin();
	while (it != s1.end())
	{
		--(*it);
		std::cout << *it;
		++it;
	}
	std::cout << std::endl;
	for (auto ch : s1)//自己实现了迭代器,范围for就可以自动识别了
	{
		std::cout << ch;
	}
	std::cout << std::endl;
}
void Test6()
{
	lhs::string s1 = "Hello world";
	lhs::string s2 = "hello world";
	std::cout << (s1 > s2) << std::endl;
	std::cout << (s1 == s2) << std::endl;
	std::cout << (s1 < s2) << std::endl;
	std::cout << (s1 >= s2) << std::endl;
	std::cout << (s1 <= s2) << std::endl;
	std::cout << (s1 != s2) << std::endl;
}
void Test7()
{
	lhs::string s1;
	std::cout << s1.capacity() << std::endl;
	s1.push_back('H');
	std::cout << s1.capacity() << std::endl;
	s1.push_back('e');
	std::cout << s1.capacity() << std::endl;
	s1.append("llo world");
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
}
void Test8()
{
	lhs::string s1 = "Hello";
	std::cout << s1.capacity() << std::endl;
	s1 += ' ';
	std::cout << s1.capacity() << std::endl;
	s1 += 'w';
	std::cout << s1.capacity() << std::endl;
	s1 += "orld";
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
}
void Test9()
{
	lhs::string s1 = "Hello world";
	s1.resize(16,'h');
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
	s1.resize(6);
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
	s1.resize(20);
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
}
void Test10()
{
	lhs::string s1 = "Hell world";
	s1.insert(4, 'o');
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
	s1.insert(0, ' ');
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
}
void Test11()
{
	lhs::string s1 = "world";
	s1.insert(0, "Hello ");
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
	s1.insert(5, " 1111");
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
}

void Test12()
{
	lhs::string s1 = "Hello444 world";
	s1.erase(5, 3);
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
	s1.erase(5);
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
}
void Test13()
{
	lhs::string s1 = "Hello";
	lhs::string s2 = "world !";
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
	std::cout << s2.size() << std::endl;
	std::cout << s2.capacity() << std::endl;
	std::cout << s2.c_str() << std::endl;
	s1.swap(s2);
	std::cout << s1.size() << std::endl;
	std::cout << s1.capacity() << std::endl;
	std::cout << s1.c_str() << std::endl;
	std::cout << s2.size() << std::endl;
	std::cout << s2.capacity() << std::endl;
	std::cout << s2.c_str() << std::endl;
}
void Test14()
{
	lhs::string s1 = "Hello world";
	std::cout << s1.find('o') << std::endl;
	std::cout << s1.find('o', 6) << std::endl;
	std::cout << s1.find("ello") << std::endl;
	std::cout << s1.find("elo") << std::endl;
}
void Test15()
{
	lhs::string s1 = "Hello";
	std::cin >> s1;
	std::cout << s1 << std::endl;
}
int main()
{
	Test1();
	Test2();
	Test3();
	Test4();
	Test5();
	Test6();
	Test7();
	Test8();
	Test9();
	Test10();
	Test11();
	Test12();
	Test13();
	Test14();
	Test15();
	return 0;
}

测试结果:


 本期代码量巨大,如有bug或不足还请各位大佬在评论区指出!

下期见~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1e-12

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值