string 核心接口的实现

本文介绍了C++中string类的基本操作,包括构造、赋值、拷贝、析构、字符访问、空间管理(reserve和resize)、追加与插入、删除、查找以及比较和输入输出重载。还涵盖了迭代器的使用和一些实用函数的实现。
摘要由CSDN通过智能技术生成

string的核心接口简介

也就是增删查改
在这里插入图片描述

先来个框架

我给的架子比较现代化,我还是比较建议注释的传统部分,不容易出错。

namespace chen
{
	class string
	{
	public:
		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_size + 1]; //后一个位置给‘\0’
			strcpy(_str, str);
		}
		
		//s1(s2)
		/*string(const string& s)
		{
			_size = s._size;
			_capacity = s._capacity;
			_str = new char[_capacity + 1];
			strcpy(_str, s._str);
		}*/
		string(const string& s)
		{ 
			_str = nullptr;     //必须给空,否则程序会崩溃掉
			string tmp(s._str);
			swap(tmp);  //s1.swap(tmp)
		}

		//s1 = s2
	/*	string& operator=(const string& s)
		{
			delete[] _str;
			_size = s._size;
			_capacity = s._capacity;
			_str = new char[_capacity + 1];
			strcpy(_str, s._str);

			return *this;
		}*/
		string& operator=(string s)   //临时对象,一份拷贝
		{
			swap(s);
			return *this;
		}

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

		char* c_str()
		{
			return _str;
		}

		void swap(string& s)
		{
			::swap(_str, s._str);          //::域操作符,访问编译器写好的全局swap函数,交换的是指针的值(类似于浅拷贝)
			::swap(_capacity, s._capacity);
			::swap(_size, s._size);
		}

	private:
		char* _str;
		size_t _capacity;
		size_t _size;

		static const size_t npos;
	};

	const size_t string::npos = -1;
	}

operator[ ]重载 和 迭代器iterator 访问

迭代器就是类似于指针的东西,不用想的太过于复杂

	typedef char* iterator;
		typedef const char* const_iterator; //const迭代器,只允许读

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
	    }

		const_iterator cbegin() const
		{
			return _str;
		}

		const_iterator cend() const
		{
			return _str + _size;
		}
         
        char& operator[](size_t pos)   //这里引用返回,表示可读可写
		{
			return _str[pos];
		}

关于空间扩容reserve和resize

1,void reserve (size_t n = 0); ,扩容,如果n小于目前已有的空间,什么事情都不做
扩容的时候不一定会扩容到指定的空间大小,因为编译器有默认的扩容机制(VS是扩2倍)

2,void resize (size_t n, char c); 调整有效字符个数,n大于有效字符个数,则填充变量c,
c默认是‘\0’
(可能发生扩容),如果小于,则删除元素,到n个。

        void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				//strcpy(tmp, _str);为什么不用strcpy呢?  
				strncpy(tmp, _str,_size+1); //记得拷贝\0
				delete[] _str;

				_str = tmp;
				_capacity = n;
			}
		}

		void resize(size_t n, char c = '\0')
		{
			if (n < _size)
			{
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				if (n > _capacity)
					reserve(n);

				for (int i = _size; i < n; i++)
					_str[i] = c;

				_str[n] = '\0';
				_size = n;
			}
		}

在这里插入图片描述

追加函数append() ,+= ,insert()

要学会代码的复用(偷懒原则)。写一个insert(),其他的基本上都ok了

//pos的位置插入字符串
		string& insert(size_t pos,const char* str)
		{
			assert(pos <= _size);

			size_t len = strlen(str);
			if (len+_size > _capacity)
			{
				reserve(len+_size);
			}
			
			//1,挪动数据,从后向前
			int end = _size;        //为什么是int? size_t 为-1就是int_max了
			while (end >= (int)pos) //为什么要强转? 会有隐式类型转换的问题
			{
				_str[end + len] = _str[end];
				end--;
			}
			strncpy(_str + pos, str, len);
			_size = len + _size;
			//这里用指针的方式挪动,或则起始位置pos在\0后一个位置也可以避免

			return *this;
		}

		//在pos的位置插入n个字符
		string& insert(size_t pos, size_t n, char c)
		{
			int len = n + _size;
			if (len > _capacity)
			{
				reserve(len);
			}

			//挪动数据,空出来n个空间
			int end = _size;
			while (end >= (int)pos)
			{
				_str[end + n] = _str[end];
				end--;
			}

			//填数据
			while (n)
			{
				n--;
				_str[pos] = c;
				pos++;
			}
			_size = len;

			return *this;
		}

		string& append(const char* s)
		{
			insert(_size, s);
			return *this;
		}

		string& append(size_t n, char c)
		{
			insert(_size, n, c);
			return *this;
		}

		string& operator+= (const string& str)
		{
			insert(_size, str._str);
			return *this;
		}

		string& operator+= (const char* s)
		{
			insert(_size, s);
			return *this;
		}
			
		void push_back(char c)
		{
			insert(_size, 1, c);
		}

删除的接口erase()

         //在pos的位置向后删除len个字符
		string& erase(size_t pos = 0, size_t len = npos)
		{
			//1,后面的元素不够删,直接在pos的位置给\0
			//2,后面的元素比较多,需要挪动删除,从前向后
			if (_size - pos < len)
			{
				_str[pos] = '\0';
				_size = pos;
			}

			else
			{
				int end = pos + len;
				while (end <= (int)_size)
				{
					_str[end - len] = _str[end];
					end++;
				}
				_size = _size - len;
			}

			return *this;
		}

		//尾删
		void pop_back()
		{
			erase(_size - 1, 1);
		}

查找函数find的接口

//从pos的位置向后找子字符串
		size_t find(const char* s, size_t pos = 0) const
		{
			assert(pos < _size);

			char* ret = strstr(_str + pos, s); 
			if (ret == nullptr)
			{
				return npos;
			}
			else
			{
				return ret - _str; //指针减指针是元素的个数,恰好是那个找到的下标位置
			}
		}

		//从pos的位置找一个字符
		size_t find(char c, size_t pos = 0) const
		{
			for (size_t i = pos; i < _size; i++)
			{
				if (_str[i] == c)
					return i;
		    }

			return npos;
		}

来一波轻松愉快的比较运算符的重载

因为比较简单也懒得动脑子代码复用了

inline bool operator>(const string& s1, const string& s2)
	{
		return (strcmp(s1.c_str(), s2.c_str()) > 0);
	}

	inline bool operator>=(const string& s1, const string& s2)
	{
		return (strcmp(s1.c_str(), s2.c_str()) >= 0);
	}
	inline bool operator<(const string& s1, const string& s2)
	{
		return (strcmp(s1.c_str(), s2.c_str()) < 0);
	}
	inline bool operator<=(const string& s1, const string& s2)
	{
		return (strcmp(s1.c_str(), s2.c_str()) <= 0);

	}
	inline bool operator==(const string& s1, const string& s2)
	{
		return (strcmp(s1.c_str(), s2.c_str()) == 0);
	}

在这里插入图片描述

输入,输出的重载


	//这里为什么没有用友元呢? 因为我并没有访问私有变量
	//而是通过公有函数间接访问的私有变量
	ostream& operator<<(ostream& out, const string& s)
	{
		for (auto& ch: s)   //范围for是需要迭代器去支持的
		{
			cout << ch;
		}
	    return out;
	}
	
    //这里需要清理掉原有的内容
	istream& operator>>(istream& in, string& s)
	{
		s.clear();
	                          //in >> c 这样用就是错误的,cin读不到空格和\n
		char c = in.get();   //cin里面的接口,类似于getchar,一次读一个字符, 可以读到空格和\n

		while (c != ' ' && c != '\n')
		{
			s.push_back(c);
			c = in.get();
		}
		return in;
	}

	//getline 是按行读取,可以读到空格的
	istream& getline(istream& in, string& s)
	{
		s.clear();

		char c;
		c = in.get();
		while (c != '\n')
		{
			s.push_back(c);
			c = in.get();
		}

		return in;
	}
  • 13
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

通过全部用例

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

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

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

打赏作者

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

抵扣说明:

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

余额充值