string类的模拟实现

157 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情


对于一个string类的实现,它的成员变量主要有:字符的指针,字符串的实际的大小,开辟该字符的容量。

char* _str;
size_t _size;//字符的实际大小
size_t _capacity;//容量

==构造函数== 对于一个字符串我们怎么初始化呢? 要分为几种情况: 1.用户没有传入任何字符 2.用户传入字符串

  • 为了解决上述的情况,我们可以提供全缺省的构造函数。 缺省参数为"",空字符串,里面只包含\0_size大小为传入参数字符串的长度 _capacity的大小就是_size的大小,当然,也可以开一定的空间。 _str开的空间要比_size要大一个,因为要储存\0

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

>==拷贝构造==

注意要深拷贝,不能直接把str._str的地址给_str,如果这样会使析构两次,非法释放空间。

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

>==析构函数==

释放开辟的空间,大小和容量归0

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

>==赋值运算符重载==

主要注意的是,要把原来_str指向的字符串释放(判断给自己赋值这种情况),然后重新开辟一段空间,然后赋值过去。

		string& operator=(const string& str)
		{
			if (_str == str._str)
				return *this;
			delete[] _str;
			_size = str._size;
			_capacity = str._capacity;
			_str = new char[_size + 1];
			strcpy(_str, str._str);
			return *this;
		}

>==+=运算符重载==

这里实现两种+=,一种是+=一个字符,另一种是+=字符串 在+=的时候要判断容量(需要有扩容的处理)

		string& operator+=(const char ch)
		{
			if (_size == _capacity)
			{
				size_t n= _capacity == 0 ? 4 : _capacity * 2;
				reserve(n);
			}
			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
			return *this;
		}
		string& operator+=(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len >= _capacity)
			{
				size_t n = _capacity == 0 ? len  : (_size + len) * 2;
				reserve(n);
			}
			strcpy(_str + _size, str);
			_size += len;
			return *this;
		}

>==npos==

静态的不可修改的公共成员 static const size_t npos = -1;


==查看字符串的长度==

		size_t size()const
		{
			return _size;
		}

==查看储存字符串的容量==

		size_t capacity()const
		{
			return _capacity;
		}

>==查看字符串是否为空==

		bool empty()const
		{
			return _size;
		}

>==清空字符串==

只把字符串变成空串,容量不变。

		void clear()
		{
			_size = 0;
			_str[_size] = '\0';
		}

>[]操作符的重载

要判断一下pos的位置是否正确。

		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}
		const char& operator[](size_t pos)const
		{
			assert(pos < _size);
			return _str[pos];
		}

==改变容量的大小== 当n小于_capacity不做处理,当n大于它时扩充容量。注意数据的保存。

		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				_capacity = n;
				char* temp = new char[_capacity+1];
				strcpy(temp, _str);
				delete[] _str;
				_str = temp;
			}
		}

==改变字符串的长度==

		void resize(size_t n, char ch='\0')
		{
			if (n <= _size)
			{
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				reserve(n);
				memset(_str + _size, ch, n - _size);
				_size = n;
			}
		}

==尾插== 在字符串的最后插入一个字符。要注意空间的容量是否够用。不够用的话就需要扩容。这里我就复用我之前写的+=运算符的重载。(还是偷懒舒服)

		string& push_back(char ch)
		{
			*this += ch;
			return *this;
		}

==append模拟实现== 这里只模拟插入一个字符串,我们会发现这不就是+=的实现嘛。

		string& append(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len == _capacity)
			{
				size_t n = _capacity == 0 ? len : (_size + len) * 2;
				reserve(n);//该函数已经把_capacity的值扩充到了n
			}
			strcpy(_str + _size, str);
			return *this;
		}

==c_str==,转换成c语言样式的字符串,注意只是只读,所以用const。

		const char* c_str()const
		{
			return _str;
		}

==查找== 从某个位置开始进行查找字符串或者查找某个字符,返回第一个匹配的位置的下标,对于查找的位置要注意是否合法,当然对于查找字符串的时候,用strstr查找到的时候会返回匹配的字符串的首个字符的地址。对于它的位置,我们用指针相减即可获得该匹配的位置。

		size_t find(char ch, size_t pos)const
		{
			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)const
		{
			assert(pos < _size);
			char* p = strstr(_str+pos, str);
			if (p == nullptr)
				return npos;
			else
			{
				return p - _str;
			}
		}