C++ STL : 模擬實現STL中的string類

string的文檔介紹

  1. string是表示字符序列的類
  2. 標準的字符串類提供了對此類對象的支持,其接口類似於標準字符容器的接口,但添加了專門用於操作 單字節字符字符串的設計特性。
  3. string類是使用char(即作爲它的字符類型,使用它的默認char_traits和分配器類型(關於模板的更多信 息,請參閱basic_string)。
  4. string類是basic_string模板類的一個實例,它使用char來實例化basic_string模板類,並用char_traits
    和allocator作爲basic_string的默認參數(根於更多的模板信息請參考basic_string)。
  5. 注意,這個類獨立於所使用的編碼來處理字節:如果用來處理多字節或變長字符(如UTF-8)的序列,這個 類的所有成員(如長度或大小)以及它的迭代器,將仍然按照字節(而不是實際編碼的字符)來操作。

下面就來模擬實現一個具備常用功能的String類

實現的接口:

默認成員函數部分
string(const char* str = ""); //全缺省構造函數
string(const string& s); //拷貝構造函數
~string(); //析構函數
string& operator=(const string& s); 
迭代器部分
//用指針模擬實現迭代器
typedef char* iterator;
typedef const char* const_iterator;
iterator begin(); //首部迭代器
iterator end();	  //尾部迭代器
const_iterator cbegin() const; //首部常量迭代器
const_iterator cend() const;   //尾部常量迭代器
容量部分
size_t capacity() const;
size_t size() const;
bool empty() const;
void resize(size_t newSize, char c = '\0');
void reserve(size_t newCapacity);
元素訪問部分
char& operator[](size_t index);
const char& operator[](size_t index) const;
關係運算符部分
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);
字符串操作部分
const char* c_str() const;
size_t find(char c, size_t pos = 0) const;
size_t find(const char* s, size_t pos = 0) const;
IO部分
friend std::ostream& operator<<(std::ostream& _cout, const string& s);
friend std::istream& operator>>(std::istream& _cin, string& s);
修改部分
static size_t npos;
string& insert(size_t pos, char c);
string& insert(size_t pos, const char* str);
string& erase(size_t pos, size_t len = npos);
void push_back(char c);
void pop_back();
string& operator+=(char c);
string& operator+=(const char* str);
void append(const char* str);
void clear();
void swap(string& s);
私有成員
size_t _size;
size_t _capacity;
char* _str;	

代碼實現

因爲代碼有點多就不分開介紹了,所有的思路都寫在註釋裏

#pragma once
#include<iostream>
#include<cstring>
#include<cassert>

namespace lee
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
		friend std::ostream& operator<<(std::ostream& _cout, const string& s);
		friend std::istream& operator>>(std::istream& _cin, string& s);

		//構造函數
		string(const char* str = "")
			: _size(strlen(str))
			, _capacity(_size)
			, _str(new char[_size + 1])
		{
			strcpy(_str, str);
		}

		/*
		//拷貝構造函數
		//傳統寫法開空間拷數據
		string(const string& s)
			: _size(s._size)
			, _capacity(s._capacity)
			, _str(new char[_size + 1])
		{
			strcpy(_str, s._str);
		}
		*/

		//現代寫法,直接構造一個臨時對象,然後和那個臨時對象進行交換,交換過去的數據在函數結束便銷燬
		string(const string& s)
			: _size(0)
			, _capacity(0)
			, _str(nullptr)
		{
			string temp(s._str);
			swap(temp);
		}

		/*
		//傳統寫法,開空間拷貝數據
		string& operator=(const string& s)
		{
			//相同則不交換
			if (this != &s)
			{
				char* str = new char[strlen(s._str) + 1];
				strcpy(str, s._str);
				delete[] _str;

				_str = str;

			}

			return *this;
		}
		*/

		//現代寫法,直接用構造函數構建然後交換
		string& operator=(const string& s)
		{
			string temp(s._str);
			swap(temp);

			return *this;
		}

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

		/*
			------------------------------------------------------------
			容量部分
			Capacity
			------------------------------------------------------------
		*/

		//返回capacity
		size_t capacity() const
		{
			return _capacity;
		}

		//返回size
		size_t size() const
		{
			return _size;
		}

		//如果爲空返回true,不爲空返回false
		bool empty() const
		{
			return !_size;
		}

		//重新分配size
		void resize(size_t newSize, char c = '\0')
		{
			//如果size不夠,擴容
			if (_size < newSize)
			{
				//如果capacity不夠,調用reserve擴容
				if (_capacity < newSize)
				{
					reserve(newSize);
				}

				//將多出的空間全部初始化爲c
				memset(_str + _size, c, newSize - _size);
			}

			//當空間夠的時候,直接截斷數據
			_size = newSize;
			_str[_size] = '\0';
		}

		//重新分配capacity
		void reserve(size_t newCapacity)
		{
			if (_capacity >= newCapacity)
				return;


			char* str = new char[newCapacity + 1];
			strcpy(str, _str);
			delete[] _str;

			_str = str;
			_capacity = newCapacity;
		}

		/*
			------------------------------------------------------------
			迭代器部分
			Iterators:
			------------------------------------------------------------
		*/

		//首部迭代器啊
		iterator begin()
		{
			return _str;
		}

		//尾部迭代器
		iterator end()
		{
			return _str + _size;
		}

		//首部常量迭代器
		const_iterator cbegin() const
		{
			return _str;
		}

		//尾部常量迭代器
		const_iterator cend() const
		{
			return _str + _size;
		}

		/*
			------------------------------------------------------------
			修改部分
			Modifiers:
			------------------------------------------------------------
		*/

		//在某個位置後插入字符
		string& insert(size_t pos, char c)
		{
			assert(pos < _size);

			if (_capacity == _size)
			{
				size_t newcapacity = (_capacity == 0) ? 2 : 2 * _capacity;

				reserve(newcapacity);
			}

			//數據後移
			for (size_t i = _size; i > pos; i--)
			{
				_str[i] = _str[i - 1];
			}


			_str[pos] = c;
			_str[++_size] = '\0';

			return *this;
		}

		//在某個位置後插入字符串
		string& insert(size_t pos, const char* str)
		{
			assert(pos < _size);
			size_t size = strlen(str);

			//檢查容量,不夠就擴容
			if (size + _size > _capacity)
			{
				reserve(size + _size);
			}

			//數據後移size個位置
			for (size_t i = _size + size - 1; i > pos + size - 1; i--)
			{
				_str[i] = _str[i - size];
			}

			//拷貝數據到第pos個位置
			memcpy(_str + pos, str, size);
			_size += size;

			return *this;
		}

		// 刪除pos位置上的元素,並返回該元素的下一個位置
		string& erase(size_t pos, size_t len = npos)
		{
			//如果那個位置後面沒有那麼多數據,就直接從那個位置截斷,刪除後面所有數據
			if (len >= _size - pos)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				//從數據刪除後前移pos個位置
				for (size_t i = pos + len; i <= _size; i++)
				{
					_str[i - len] = _str[i];
				}
			}

			//重新設置size和結尾的\0
			_size -= len;
			_str[_size] = '\0';
			return *this;
		}
		//尾插

		void push_back(char c)
		{
			if (_capacity == _size)
			{
				size_t newcapacity = (_capacity == 0) ? 2 : 2 * _capacity;

				reserve(newcapacity);
			}

			_str[_size++] = c;
			_str[_size] = '\0';
		}

		//尾刪
		void pop_back()
		{
			_str[--_size] = '\0';
		}

		//追加字符
		string& operator+=(char c)
		{
			push_back(c);

			return *this;
		}

		//尾部追加字符串
		void append(const char* str)
		{
			size_t size = strlen(str);

			//檢查容量,不夠就擴容
			if (size + _size > _capacity)
			{
				reserve(size + _size);
			}

			//尾部追加字符串
			strcpy(_str + _size, str);
			_size += size;
		}

		//追加字符串
		string& operator+=(const char* str)
		{
			append(str);

			return *this;
		}

		//清空string
		void clear()
		{
			_size = 0;
			_str[_size] = '\0';
		}

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



		/*
			------------------------------------------------------------
			元素訪問部分
			Element 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)
		{
			if (strcmp(_str, s._str) == -1)
				return true;
			else
				return false;
		}

		bool operator<=(const string& s)
		{
			return (*this < s) || (*this == s);
		}

		bool operator>(const string& s)
		{
			return !(*this <= s);
		}

		bool operator>=(const string& s)
		{
			return !(*this < s);
		}

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

		bool operator!=(const string& s)
		{
			return !(*this == s);
		}

		/*
		------------------------------------------------------------
		字符串操作
		String operations:
		------------------------------------------------------------
		*/
		//返回C風格的字符串
		const char* c_str() const
		{
			return _str;
		}

		//查找字符c第一次出現的位置
		size_t find(char c, size_t pos = 0) const
		{
			assert(pos < _size);
			size_t i = pos;

			while (i < _size)
			{
				if (_str[i] == c)
					return i;

				i++;
			}

			return npos;
		}

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

			while (*src)
			{
				//如果兩個位置匹配則繼續遍歷
				while (*src == *sub && *sub)
				{
					src++;
					sub++;
				}
				//如果sub走完就說明完全匹配,返回sub第一次出現的位置
				if ('\0' == *sub)
				{
					return (src - _str - strlen(s));
				}
				//不匹配則回溯,繼續匹配下一個位置
				else
				{
					sub = sub;
					src = ++src;
				}
			}

			return npos;
		}


	private:
		size_t _size;
		size_t _capacity;
		char* _str;
		static size_t npos;
	};

	size_t string::npos = -1;

	std::ostream& operator<<(std::ostream& out, const string& s)
	{
		out << s._str;
		return out;
	}

	std::istream& operator>>(std::istream& in, string& s)
	{
		//直接用cin輸入進str會有無法擴容的問題,需要手動擴容
		while (1)
		{
			char ch;
			ch = in.get();
			//遇到分隔符則暫停
			if (ch == '\n' || ch == ' ')
			{
				break;
			}
			else
			{
				s.push_back(ch);
			}
		}
		
		return in;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章