【C++初阶】探索STL之——String类的模拟实现

1.string类

string说白了就是用来储存字符串的,所以它的底层结构也不是很复杂,只是为了使用起来方便,就对他进行了简单的封装。

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

这里定义了一个字符串指针来储存字符串,_size用来记录字符串的长度,_capacity用来记录字符串的容量

2.string类的构造和赋值实现

//默认构造
string ()//带参构造
string(const char*str="")//拷贝构造
string(const string&s)//赋值
string& operator =(const string& s)

代码实现

//默认构造
string():_str(new char[1]{'\0'}),_size(0),_capacity(0)
{}

//带参构造
string(const char* str ="")
{
	int len = strlen(str);

	_str = new char[len + 1];
	strcpy(_str, str);
	_size = len;
	_capacity = len + 1;
}

//拷贝构造
//深拷贝
string(const string& s)
{
	_str = new char[s._capacity + 1];
	strcpy(_str, s._str);
	_size = s._size;
	_capacity = s._capacity;
}

//赋值
string& operator =(const string& s)
{
	delete[]_str;//释放旧空间

	_str = new char[s._capacity+1];
	
	strcpy(_str,s._str);
	_size = s._size;
	_capacity = s._capacity;
	return *this;
}

这里要注意的是,默认构造函数那里要给 _str 开一个空间储存 ‘\0’ ,还有带参构造那儿给了一个空字符,目的是了确保对象始终处于有效的状态,避免引发其他的问题。

3.类的析构实现

~string()
{}

代码实现

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

4.类的iterator

 // iterator

    iterator begin();

    iterator end()

代码实现

//iterator
iterator begin()
{
	return _str;
}

iterator end()
{
	return _str + _size;
}

这里都是返回该位置的迭代器

5.类的修改(Modify)实现

  // modify

    void push_back(char c);

    string& operator+=(char c);

    void append(const char* str);

    string& operator+=(const char* str);

    void clear();

    void swap(string& s);

    const char* c_str()const;

代码实现:

// modify

void push_back(char c)
{
	//判断是否需要扩容
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : 2 * _capacity);
	}
	_str[_size] = c;
	_size++;
	//这个地方特别容易忘记
	_str[_size] = '\0';
}

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

void append(const char* str)
{
	//判断是否需要扩容
	size_t len = _size + strlen(str);
	if (len > _capacity)
	{
		reserve(len < 2 * _capacity ? 2 * _capacity : len);
	}
	for (int i = 0; i < strlen(str); i++)
	{
		_str[_size] = str[i];
		_size++;
	}

	//一定要注意
	_str[_size] = '\0';
}

string& operator+=(const char* str)
{
	append(str);
	return *this;
}

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

void swap(string& s)
{
	std::swap(_str,s._str);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

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

这个部分代码的实现特别需要注意的是 ‘\0’ 的处理,如果没有注意后续会出现很多问题

6.类的capacity实现

// capacity

    size_t size()const

    size_t capacity()const

    bool empty()const

    void resize(size_t n, char c = '\0');

    void reserve(size_t n);

代码实现:

// capacity

size_t size()const
{
	return _size;
}

size_t capacity()const
{
	return _capacity;
}

bool empty()const
{
	return _size == 0;
}

void resize(size_t n, char c = '\0')
{
	if (n < _size)//n<_size时
	{
		_size = n;
		_str[n] = '\0';
	}
	else if (n > _size)//n>_size时
	{
	  //判断是否需要扩容
		if (n > _capacity)
		{
			reserve(n);
		}

		for (int i = _size; i < n; i++)
		{
			_str[i] = c;
		}
		_size = n;
		_str[_size] = '\0';

	}
	
}

void reserve(size_t n)
{
	char* tmp = new char[n + 1];//创建新空间
	strcpy(tmp, _str);//拷贝旧空间
	delete[]_str;//释放旧空间
	_str = tmp;//指向新空间
	_capacity = n;
}

这部分的代码就resize可能实现起来有点麻烦,在我看来只要你对resize这个函数的作用理解清楚了,实现起来还是挺容易的,按着各种情况写就行了。

7.类access的实现

  // access

    char& operator[](size_t index);

    const char& operator[](size_t index)const;

代码实现:

// access

char& operator[](size_t index)
{
	assert(index < _size);//如果index>_size就会弹出警告
	return _str[index];
}

const char& operator[](size_t index)const
{
	assert(index < _size);//如果index>_size就会弹出警告
	return _str[index];
}

8.类relational operators的实现

 //relational operators

    bool operator<(const string& s);

    bool operator<=(const string& s);

    bool operator>(const string& s);

    bool operator>=(const string& s);

    bool operator==(const string& s);

    bool operator!=(const string& s);


代码实现

bool operator<(const string& s)
{
	return strcmp(_str, s._str) < 0;
}

bool operator<=(const string& s)
{
	return strcmp(_str, s._str) < 0 || strcmp(_str, s._str)==0;
}

bool operator>(const string& s)
{
	return strcmp(_str, s._str) > 0;
}

bool operator>=(const string& s)
{
	return strcmp(_str, s._str) > 0 || strcmp(_str, s._str)==0;
}

bool operator==(const string& s)
{
	return strcmp(_str, s._str) == 0;
}

bool operator!=(const string& s)
{
	return strcmp(_str, s._str)!=0;
}

这里我们巧妙的运用了strcmp函数,我们只需要知道strcmp返回值对应的结果就行了,这里是strcmp返回值的说明。

在这里插入图片描述

9.类find、insert、erase的实现

// 返回c在string中第一次出现的位置
size_t find (char c, size_t pos = 0) const;

// 返回子串s在string中第一次出现的位置
size_t find (const char* s, size_t pos = 0) const;

// 在pos位置上插入字符c/字符串str,并返回该字符的位置
string& insert(size_t pos, char c);
string& insert(size_t pos, const char* str);

// 删除pos位置上的元素,并返回该元素的下一个位置
string& erase(size_t pos, size_t len);

代码实现

// 返回c在string中第一次出现的位置

size_t find(char c, size_t pos = 0) const
{
	assert(pos <= _size);
	for (int i = pos; i < _size; i++)
	{
		if (_str[i] == c)
		{
			return i;
		}
	}
	//没找到
	return npos;
}

// 返回子串s在string中第一次出现的位置

size_t find(const char* s, size_t pos = 0) const
{
	assert(pos < _size);

	char* ptr = strstr(_str+pos, s);
	if (ptr == nullptr)
	{
		return npos;
	}
	else
	{
		return ptr - _str;
	}

}

// 在pos位置上插入字符c/字符串str,并返回该字符的位置

string& insert(size_t pos, char c)
{
	assert(pos<=_size);
	//判断是否需要扩容
	if (_size == _capacity)
	{
		reserve(_capacity==0?4:2*_capacity);
	}
   
   //进行移位置
	size_t tmp = _size;
	while (tmp > pos)
	{
		_str[tmp] = _str[tmp - 1];
		tmp--;
	}
	//插入数据
	_str[pos] = c;
	//更新_size
	_size++;
	_str[_size] = '\0';
	return *this;
}

string& insert(size_t pos, const char* str)
{
	assert(pos<=_size);
	if (str == nullptr)
	{
		return *this;
	}
	//判断是否需要扩容
	if (_size + strlen(str) > _capacity)
	{
		if((_size+strlen(str)<2*_capacity?_size+strlen(str):2*_capacity));
	}


	size_t len = strlen(str);
	size_t tmp = _size + len;

	while ((tmp - len) >= pos)
	{
		_str[tmp] = _str[tmp - len];
		tmp--;
	}

	for (int i = 0; i < len; i++)
	{
		_str[pos] = str[i];
		pos++;
	}
	_size += len;
	_str[_size] = '\0';
	return *this;
	
}



// 删除pos位置上的元素,并返回该元素的下一个位置

string& erase(size_t pos, size_t len)
{
	assert(pos < _size);

	if (len > _size - pos)
	{
		_str[pos] = '\0';
		_size = pos;
	}


	size_t tmp = pos;
	while (tmp != _size)
	{
		_str[tmp] = _str[tmp + 1];
		tmp++;
	}
	_size -= len;;
	_str[_size] = '\0';
	return *this;
}

这部分代码需要注意的地方很多,所以可以在写之前画画图,借助图像的理解实现起来就不会感到困难了。

10.operator>>和operator <<的实现

ostream& operator<<(ostream& out, const string& s)

istream& operator>>(istream& in, string& s)

代码实现

    ostream& operator<<(ostream& out, const string& s)
	{
		for (auto ch : s)
		{
			out << ch;
		}

		return out;
	}
	
	istream& operator>>(istream& in, string& s)
	{
		s.clear();

		const int N = 256;
		char buff[N];
		int i = 0;

		char ch;
		ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N-1)
			{
				buff[i] = '\0';
				s += buff;

				i = 0;
			}

			//in >> ch;
			ch = in.get();
		}

		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}

		return in;
	}

11.string类的模拟实现全部代码

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;


namespace sanmu
{
	class string
	{
		typedef char* iterator;
		public:
		//默认构造
		string() :_str(new char[1] {'\0'}), _size(0), _capacity(0)
		{}

		//带参构造
		string(const char* str = " ")
		{
			int len = strlen(str);

			_str = new char[len + 1];
			strcpy(_str, str);
			_size = len;
			_capacity = len + 1;
		}

		//拷贝构造(深拷贝)
		string(const string& s)
		{
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
			_size = s._size;
			_capacity = s._capacity;
		}

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

			return *this;
		}

		//iterator
		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		


		// modify

		void push_back(char c)
		{
			//判断是否需要扩容
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			}
			_str[_size] = c;
			_size++;
			//这个地方特别容易忘记
			_str[_size] = '\0';
		}

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

		void append(const char* str)
		{
			//判断是否需要扩容
			size_t len = _size + strlen(str);
			if (len > _capacity)
			{
				reserve(len < 2 * _capacity ? 2 * _capacity : len);
			}
			for (int i = 0; i < strlen(str); i++)
			{
				_str[_size] = str[i];
				_size++;
			}

			//一定要注意
			_str[_size] = '\0';
		}

		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}

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

		void swap(string& s)
		{
			std::swap(_str,s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

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

		// capacity

		size_t size()const
		{
			return _size;
		}

		size_t capacity()const
		{
			return _capacity;
		}

		bool empty()const
		{
			return _size == 0;
		}

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

				for (int i = _size; i < n; i++)
				{
					_str[i] = c;
				}
				_size = n;
				_str[_size] = '\0';

			}
			
		}

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

		// access

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

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

		//relational operators

		bool operator<(const string& s)
		{
			return strcmp(_str, s._str) < 0;
		}

		bool operator<=(const string& s)
		{
			return strcmp(_str, s._str) < 0 || strcmp(_str, s._str)==0;
		}

		bool operator>(const string& s)
		{
			return strcmp(_str, s._str) > 0;
		}

		bool operator>=(const string& s)
		{
			return strcmp(_str, s._str) > 0 || strcmp(_str, s._str)==0;
		}

		bool operator==(const string& s)
		{
			return strcmp(_str, s._str) == 0;
		}

		bool operator!=(const string& s)
		{
			return strcmp(_str, s._str)!=0;
		}

		// 返回c在string中第一次出现的位置

		size_t find(char c, size_t pos = 0) const
		{
			assert(pos <= _size);
			for (int i = pos; i < _size; i++)
			{
				if (_str[i] == c)
				{
					return i;
				}
			}
			//没找到
			return npos;
		}

		// 返回子串s在string中第一次出现的位置

		size_t find(const char* s, size_t pos = 0) const
		{
			assert(pos < _size);

			char* ptr = strstr(_str+pos, s);
			if (ptr == nullptr)
			{
				return npos;
			}
			else
			{
				return ptr - _str;
			}

		}

		// 在pos位置上插入字符c/字符串str,并返回该字符的位置

		string& insert(size_t pos, char c)
		{
			assert(pos<=_size);
			if (_size == _capacity)
			{
				reserve(_capacity==0?4:2*_capacity);
			}

			size_t tmp = _size;
			while (tmp > pos)
			{
				_str[tmp] = _str[tmp - 1];
				tmp--;
			}
			_str[pos] = c;
			_size++;
			_str[_size] = '\0';
			return *this;
		}

		string& insert(size_t pos, const char* str)
		{
			assert(pos<=_size);
			if (str == nullptr)
			{
				return *this;
			}
			if (_size + strlen(str) > _capacity)
			{
				if((_size+strlen(str)<2*_capacity?_size+strlen(str):2*_capacity));
			}


			size_t len = strlen(str);
			size_t tmp = _size + len;

			while ((tmp - len) >= pos)
			{
				_str[tmp] = _str[tmp - len];
				tmp--;
			}

			for (int i = 0; i < len; i++)
			{
				_str[pos] = str[i];
				pos++;
			}
			_size += len;
			_str[_size] = '\0';
			return *this;
			
		}



		// 删除pos位置上的元素,并返回该元素的下一个位置

		string& erase(size_t pos, size_t len)
		{
			assert(pos < _size);

			if (len > _size - pos)
			{
				_str[pos] = '\0';
				_size = pos;
			}


			size_t tmp = pos;
			while (tmp != _size)
			{
				_str[tmp] = _str[tmp + 1];
				tmp++;
			}
			_size -= len;;
			_str[_size] = '\0';
			return *this;
		}

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

		static size_t npos;
	};
}


制作不易,还请三连!感谢大佬们的观看!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值