C++ 模拟实现string的一部分

前言:

仅模拟实现string的一部分。实现的目的是:加深对string的理解。
模拟实现的包含以下下内容:

  1. swap()
  2. 构造函数
  3. 拷贝构造函数
  4. 析构函数
  5. =
  6. []
  7. size()
  8. capcity()
  9. 迭代器
  10. reserve
  11. resize
  12. insert
  13. push_back
  14. append
  15. +=
  16. earse
  17. find
  18. npos
  19. << 和 >>

源码展示:(解析位于注释中)

在.cpp文件中:

#define _CRT_SECURE_NO_WARNINGS 1
#include<string>
#include<iostream>
using namespace std;
#include <assert.h>
#include"my_string.h"

//用于测试
int main()
{
    
    
	return 0;
}

在.h文件中:(通常来说,应该再开一和cpp文件定义声明分离,在练习这这样定义和声明不分离方便点)

#pragma once

namespace myString
{
    
    
	class string
	{
    
    
	public:

		//实现swap
		void swap(string& s)
		{
    
    
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capcity, s._capcity);
		}



		//实现构造函数 1- string s  //实现构造函数 2— string s("xxxxx");
		string(const char* str = "")
			:_size(strlen(str)) //这里的strlen还是用的编译器的string库里的
			, _capcity(_size)
		{
    
    
			_str = new char[_capcity + 1]; // + 1 是为了存放/0 ;
			strcpy(_str, str);
		}

		实现构造函数 3- string s1(s2)---浅拷贝
		//string(const string& s)
		//	:_size(strlen(s._str))
		//	,_capcity(_size)
		//{
    
    
		//	_str = new char[_capcity + 1];
		//	strcpy(_str, s._str); 
		//}
	


		//实现深度拷贝——4 string s1(s2)  现代写法
		string(const string& s)
			:_str(nullptr)
			, _size(0)
			, _capcity(0)
		{
    
    
			string tmp(s._str);//tmp在出函数时会被析构函数销毁
			swap(tmp);
		}


		//实现析构函数 
		~string()
		{
    
    
			if (_str != nullptr)
			{
    
    	
				delete[] _str;
				_str = nullptr;
				_size = _capcity = 0;
			}
		}

		//赋值符号 = 重载的实现
		string& operator=(string s) //因为此处 string s 为实参拷贝,所以不会改变原s
		{
    
    
			swap(s);
			return *this;
		}


		//实现 c_str
		//返回值为const + 指针 代表指针指向的空间不可改变  ; 函数后加 const 指定this指针指向的空间不可被修改
		const char* c_str() const 
		{
    
    
			return _str;
		}
		//实现[],可对 _str进行修改的
		char& operator[](size_t pos)
		{
    
    
			assert(pos < _size);
			return _str[pos];
		}
		//实现[],不可对 _str进行修改的
		const char& operator[](size_t pos) const
		{
    
    
			assert(pos < _size);
			return _str[pos];
		}



		//实现size()
		size_t size() const
		{
    
    
			return _size;
		}
		size_t capcity()const
		{
    
    
			return _capcity;
		}

		//实现迭代器
		typedef char* iterator;
		typedef const char* const_iterator; //const_iterator 

		const_iterator begin() const
		{
    
    
			return _str;
		}
		const_iterator end() const
		{
    
    
			return _str + _size;
		}
		iterator begin()
		{
    
    
			return _str;
		}
		iterator end()
		{
    
    
			return _str + _size;
		}



		//实现reserve 功能为保留n个空间
		void reserve(size_t n)
		{
    
    
			if ( n <= _capcity)
			{
    
    
				return;
			}
			else
			{
    
    	//new 开辟空间一般不会失败
				char* tmp = new char[n + 1];
				assert(tmp);
				strcpy(tmp, _str);
				delete[] _str;  // 关键的、容易忘记的 !!!!!
				_str = tmp; //这样写直接改变this指针中_str,不需要返回值
				_capcity = n;
			}
		}



		//实现resize resize功能:n > capcity 开辟到n个空间,并且开辟的空间用字符c初始化
		// n < capcity 删除部分数据,保留n个数据,但空间不变。
		void resize(size_t n, char c ='\0')
		{
    
    
			if (n <= _capcity)
			{
    
    
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
    
    
				reserve(n);//_capcity已经改变,但_size还没有被改变
				for(int i = _size ; i < n ; i ++ )
				{
    
    
					_str[i] = c;
				}
				_size = n;
				_str[_size] = '\0';
			}
		}



		//实现insert1 在pos位置插入一个字符c
		string& insert(size_t pos, char c)
		{
    
    
			assert(pos <= _size);
			if (_size == _capcity)
			{
    
    
				reserve(_capcity == 0 ? 4 : _capcity * 2);
			}
			size_t end = _size + 1;
			while (end > pos)
			{
    
    
				_str[end] = _str[end - 1];
				end--;
			}
			_str[pos] = c;
			_size++;
			
			return *this;
		}



		//实现insert2 在pos位置插入字符串c
		string& insert(size_t pos, const char* c)
		{
    
    
			assert(pos <= _size);
			size_t len = strlen(c);
			if (_size + len > _capcity)
			{
    
    
				reserve(_size + _capcity);
			}
			size_t end = _size + len;
			while (end > pos + len - 1)
			{
    
    
				_str[end] = _str[end - len];
				--end;
			}
			strncpy(_str + pos, c, len);
			_size = _size + len;
			return *this;
		}



		//实现 push_back() pushback作用是在对象字符串末尾加一个字符
		void push_back(char c)
		{
    
    
			if (_size == _capcity)
			{
    
    
				reserve(_capcity == 0 ? 4 : _capcity * 2);
			}
			_str[_size] = c;
			_size++;
			_str[_size] = '\0';
		}



		void append(const char* str)
		{
    
    
			insert(_size, str);
		}



		//实现对 += 的重载
		string& operator+=(char ch) //为何不用 char& ch 呢? 因为大型对象时引用传参效率提升才明显
		{
    
    
			push_back(ch);
			return *this;
		}
		string& operator+=(char* str)
		{
    
    
			append(str);
			return *this;
		}


		//实现earse函数
		string& earse(size_t pos, size_t len = npos) //如果不给第二个值那就删除pos之后的所有
		{
    
    
			assert(pos < _size);

			if(len == npos || pos + len >= _size)
			{
    
    
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
    
    
				size_t begin = len + pos;
				while (begin <= _size) //因为要把‘\0’也拷过去
				{
    
    
					_str[begin - len] = _str[begin];
					begin++;
				}
				_size -= len;
			}
			return *this;
		}



		//实现find函数 ,从字符串的pos位置开始查找,返回第一个所查字符所在位置的下标,如果没有则返回npos
		size_t find(char c, size_t pos = 0)
		{
    
    
			while (pos < _size)
			{
    
    
				if (_str[pos] == c)
				{
    
    
					return pos;
				}
				pos++;
			}
			return npos;
		}



		//实现find函数2,查找子窜,返回子窜第一个字符下标;//这个实现的机制是暴力匹配,网络上有高效字符串匹配的方法,这里直接用strstr实现
		size_t find(const char* str, size_t pos = 0)
		{
    
    
			const char* p = strstr(_str + pos, str);
			if (p == nullptr)
			{
    
    
				return npos;
			}
			else
			{
    
    
				return p - _str; //下标(相对位置)
			}
		}


	private:
		//_size顺序不能变,因为初始化列表实际上是对着private里的成员声明顺序进行初始化的。
		char* _str;
		size_t _size;
		size_t _capcity;
		//C++11仅不允许在类声明中初始化static非const类型的数据成员。
		const static size_t npos; //即为最大值
	};



	const size_t string::npos = -1;



	//为啥运算符重载在类外定义
	ostream& operator<<(ostream& out, const string& s)
	{
    
    
		for (auto ch : s) //依据迭代器实现 
		{
    
    
			out << ch;
		}
		return out;
	}



	istream& operator>>(istream& in, string& s)
	{
    
    
		char ch;
		ch = in.get();
		/*	get(void) 用来从指定的输入流中提取一个字符(包括空白字符),
			函数的返回值就是读入的字符。
			若遇到输入流中的文件结束符,则函数值返回文件结束标志EOF*/
		char buff[128] = {
    
     '\0' }; //因为一次最多输入128
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
    
    
			buff[i++] = ch;
			if (i == 127)
			{
    
    
				s += buff;
				memset(buff, '\0', 128);
				/*memset函数 ,内存设置函数 memset
				(地址,设置的必须为整形的内容x,改变的字节数n)
				用整形内容x替换地址容器中前n个字节的内容*/
				i = 0;
			}
			ch = in.get();
		}
		s += buff;
		return in;
	}
}






猜你喜欢

转载自blog.csdn.net/WSK1454360679/article/details/130353928