天天看點

模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結

string的模拟實作

  • 1 先來介紹一下string
  • 2 常見用法
    • 2.1 成員函數
  • 3 模拟實作
    • 3.1 基礎接口實作
    • 3.2 疊代器
    • 3.3 operator[]實作
    • 3.4 容量部分實作
    • 3.5 擴容(insert、push_back、append、+=)
    • 3.6 清理
    • 3.7 關系運算
      • 類内實作:
      • 類外實作:
    • 3.8 流運算(>>,<<,getline)
  • 4 總結

1 先來介紹一下string

概述:string是C++标準庫裡面的一個重要部分,其主要工作是用于字元串處理。

2 常見用法

2.1 成員函數

具體實作原理詳見此網站。

模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結
模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結
模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結
模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結
模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結

3 模拟實作

class類的定義:

class string
{
public:
	//具體函數實作,見下面部分給出
	
	static const size_t npos;//類外定義
private:
	char* _str;
	size_t _size;
	size_t _capacity;//存儲有效字元
};
const size_t string::npos = -1;
           

3.1 基礎接口實作

構造函數+拷貝構造函數+析構函數+指派構造函數:

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

		//現代寫法的swap成員函數 簡化程式代碼
		void swap(string& s)
		{
			/*std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);*/

			//域作用限定符,全局域
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}

		//s2(s1)拷貝構造
		string(const string &s)
			:_str(nullptr)
			, _capacity(0)
			, _size(0)
		{
			string temp(s._str);
			// 多個交換
			/*swap(_str, temp._str);
			swap(_size, temp._size);
			swap(_capacity, temp._capacity);*/

			// 隐含 this->swap(temp);
			swap(temp);//就近原則,使用的是局部的swap,目前類域找
		}

		string& operator=(string s)
		{
			/*swap(_str, s._str);
			swap(_size, s._size);
			swap(_capacity, s._capacity);*/
			swap(s);

			return *this;
		}

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

3.2 疊代器

//          疊代器
		typedef char* iterator;
		typedef const char* const_itertor;

		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size; //end位置是\0位置
		}
		const iterator begin() const
		{
			return _str;
		}
		const iterator end() const
		{
			return _str + _size;
		}
           

3.3 operator[]實作

// &保證了 可讀可寫,出了作用域對象還在
		char& operator[](size_t i) 
		{
			assert(i < _size);//防止越界
			return _str[i];
		}

		//隻能讀
		const char& operator[](size_t i) const
		{
			assert(i < _size);
			return _str[i];
		}
           

3.4 容量部分實作

此部分主要實作的是size,capacity,判斷是否為空,reserve,resize接口。

這裡主要分析reserve接口和resize接口:

模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結
// capacity
		size_t size()
		{
			return _size;
		}
		size_t size() const
		{
			return _size;
		}
		size_t capacity()const
		{
			return _capacity;
		}
		bool empty()const
		{
			return _size == 0;
		}
		//開空間 改變容量
		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* temp = new char[n + 1];
				//strcpy(temp, _str);
				strncpy(temp, _str,_size+1);
				delete[]_str;

				_str = temp;
				_capacity = n;
			}
		}

		//開空間,初始化,縮小,size也變換
		void resize(size_t n, char ch = '\0')
		{
			//空間足
			if (n < _size)
			{
				//縮小,插入\0,迫使其在n的位置終止
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				//容量不夠,擴容
				if (n > _capacity)
				{
					reserve(n);
				}
				// n<capacity 
				for (size_t i = _size; i < n; ++i)
				{
					_str[i] = ch;//插入字元
				}
				_str[n] = '\0';//末尾為結束标志
				_size = n;//記錄容量
			}
		}
           

3.5 擴容(insert、push_back、append、+=)

首先分析如何insert一個字元:

模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結

其次,再次分析如何insert一個字元串:

模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結
模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結
模拟實作string(v1)1 先來介紹一下string2 常見用法3 模拟實作4 總結
string&  insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			//容量已滿
			if (_size == _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 16 : _capacity * 2;
				reserve(newcapacity);//擴容
			}

			//移動pos位置及之後字元
			//寫法一 不推薦
			/*	int end = _size;
			while (end >= (int)pos) // 避免0 - 1加(int)
			{
				_str[end+1] = _str[end];
				--end;
			}
			_str[pos] = ch;
			_size++;

			return *this;
			*/

			//寫法二 推薦
			int end = _size + 1;
			while (end > pos)
			{
				_str[end] = _str[end - 1];
				--end;
			}
				
			//寫法3 someproblem
			/*char* end = _str + _size;
			while (end >= _str + pos)
			{
				*(end + 1) = *end;
				--end;
			}*/

			_str[pos] = ch;
			_size++;

			return *this;
		}

		//pos位置之前 insert 字元串
		void insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}

			//空間足 挪動  *****分析界限問題*****
			//分析實作辦法 一
			/*	size_t end = _size + len;
			while (end >= (int)(pos + len))
			{
			_str[end] = _str[end - len];
			--end;
			}*/

			//實作辦法 二
			/*	cout << "size: " << _size << endl;
			cout << "_str[4]: " << _str[4] << endl;
			cout << "_str[8]: " << _str[8] << endl;*/
			size_t end = _size + len + 1;
			//cout << "end:" << end << endl;
			while (end > pos + len)
			{
				_str[end - 1] = _str[end - len - 1];//先從結束\0 開始向後移動
				--end;
			}
			//cout << "end: "<< end << endl;

			//指針辦法解決
			/*char*end = _str + _size;
			while (end >= _str + pos)
			{
				*(end + len) = *end;
				--end;
			}*/			
			strncpy(_str + pos, str, len);
			_size += len;
		}

		//*****************************
		//修改 
		void push_back(char ch)
		{
			//if (_size == _capacity)
			//{
			//	//擴容
			//	reserve(2 * _capacity);
			//}
			//_str[_size] = ch;
			//++_size;
			//_str[_size] = '\0';//保證字元串終止

			insert(_size, ch);
		}
		void append(const char* str)
		{
			//size_t len = _size + strlen(str);
			//if (len > _capacity)
			//{
			//	//擴容
			//	reserve(len);
			//}

			//strcpy(_str + _size, str);
			//_size = len;
			insert(_size, str);
		}

		//this 指針處理 
		string&  operator+=(char ch)
		{
			push_back(ch);
			return *this;//深拷貝
		}

		//+= 字元串
		string&  operator+=(const  char*  str)
		{
			append(str);
			return *this;//深拷貝
		}
           

3.6 清理

void clear()
		{
			_size = 0;
			_str[_size] = '\0';
		}
		
		void erase(size_t pos, size_t len = npos)
		{
			assert(pos < _size);
			//删完、删的len超過_size
			if (len == npos || pos+len >= _size)
			{
				_str[pos] = '\0';//直接設為字元串終止
				_size = pos;//修改大小
			}
			else//删除一小段
			{
				strcpy(_str + pos, _str + pos + len);//字元串向前覆寫移動
				_size -= len;
			}

		}

		//找一個字元
		size_t find(char ch, size_t pos = 0)
		{
			for (size_t i = pos; i < _size; ++i)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}

		//找一個字元串
		size_t find(const char* sub, size_t pos = 0)
		{
			const char* ret = strstr(_str + pos, sub);
			if (ret == nullptr)
			{
				return npos;
			}
			else
			{
				return ret - _str;
			}
		}
           

3.7 關系運算

類内實作:

// 類内實作關系運算
		//relational operators
		bool operator<(const string& s)const
		{
			int res = strcmp(_str, s._str);
			if (res < 0)
				return true;
			return false;
		}
		bool operator<=(const string& s)const
		{
			return !(*this > s);
		}
		bool operator>(const string& s)const
		{
			int res = strcmp(_str, s._str);
			if (res > 0)
				return true;
			return false;
		}
		bool operator>=(const string& s)const
		{
			return !(*this < s);
		}
		bool operator==(const string& s)const
		{
			int res = strcmp(_str, s._str);
			if (res == 0)
				return true;
			return false;
		}
		bool operator!=(const string& s)const
		{
			return !(*this == s);
		}
           

類外實作:

實作辦法一:利用strcmp函數實作

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

	bool operator <=(const string&s1, string &s2)
	{
		return s1<s2 || s1 == s2;
	}

	bool operator >(const string&s1, string &s2)
	{
		return !(s1 <= s2);
	}

	bool operator >=(const string&s1, string &s2)
	{
		return !(s1 < s2);
	}
           

實作辦法二:自己模拟實作比大小

bool operator>(const string&s1, const string&s2)
	{
		size_t i1 = 0, i2 = 0;
		while (i1 < s1.size() && i2 < s2.size())
		{
			if (s1[i1] > s2[i2])
			{
				return true;
			}
			else if (s1[i1] < s2[i2])
			{
				return false;
			}
			else
			{
				++i1;
				++i2;
			}
		}

		if (i1 < s1.size())
		{
			return true;
		}
		else if (i2<s2.size())
		{
			return false;
		}
		else
		{
			return false;
		}
	}

	bool operator==(const string& s1, const string& s2)
	{
		size_t i1 = 0, i2 = 0;
		while (i1 < s1.size() && i2 < s2.size())
		{
			if (s1[i1] > s2[i2])
			{
				return false;
			}
			else if (s1[i1] < s2[i2])
			{
				return false;
			}
			else
			{
				++i1;
				++i2;
			}
		}

		if (i1 == s1.size() && i2 == s2.size())
		{
			return true;
		}
		else
		{
			return false;
		}
	}
           

3.8 流運算(>>,<<,getline)

ostream& operator<<(ostream& out, const string& s)
	{
		//方法一 :範圍for解決
		for (auto ch : s)
		{
			out << ch;
		}

		//方法二
		/*for (size_t i = 0; i < s.size(); ++i)
		{
			out << s[i];
		}*/
		return out;
	}

	istream& operator>>(istream& in, string&s)
	{
		s.clear();
		//s.resize(0);//清理 == clear
		char ch;
		ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			s += ch;
			//in>>ch;
			in.get(ch); //擷取
		}
		return in;
	}

	//Getline 操作
	istream& getline(istream& in, string& s)
	{
		s.clear();
		//s.resize(0);//清理 == clear
		char ch;
		ch = in.get();
		while (ch != '\n')
		{
			s += ch;
			//in>>ch;
			in.get(ch); //擷取
		}
		return in;
	}
           

4 總結

整體實作+測試代碼點選此處。

關于string類的一些東西,融彙貫通,多比較練習。

繼續閱讀