(C++初阶) string 类的模拟实现

目录

一 string 的一些总结

1 string是一个管理字符数组的类,要求这个字符数组结尾用‘\0’标识。

2 const 修饰成员函数

二 string 类的模拟实现

1 传统版写法的string类

2 现代版写法的string类

3 增

4 删

5 查

6 改

7 遍历

8 比较运算符重载


一 string 的一些总结

1 string是一个管理字符数组的类,要求这个字符数组结尾用‘\0’标识。

①拷贝构造和赋值重载实现深拷贝。

②增删查改的相关接口(和顺序表类似)。

③重载的一些常见运算符。如:>、<、<<、>>、[ ] 等等。

④迭代器

2 const 修饰成员函数

①成员函数const修饰的是*this ,本质是保护成员变量在函数体内不会被改变,相当于是this指向的对象成员被保护,不能修改。

②不修改成员变量的函数都应该加const,但是本身就是修改数据的接口,比如 push_back/insert/erase等,是不加const的。有些函数,应该提供const版本和普通版本,如迭代器和 operator[ ]。

二 string 类的模拟实现

传统版写法的string

class string
{
public:
 string(const char* str = "")
 { 
 // 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下
if(nullptr == str)
 {
 assert(false);
 return;
 }
 
 _str = new char[strlen(str) + 1];
 strcpy(_str, str);
 }
 
 string(const string& s)
 : _str(new char[strlen(s._str)+1])
 {
 strcpy(_str, s._str);
 }
 
 string& operator=(const string& s)
 {
 if(this != &s)
 {
 char* pStr = new char[strlen(s._str) + 1];
 strcpy(pStr, s._str);
 delete[] _str;
 _str = pStr;
 }
 
 return *this;
 }
 
 ~string()
 {
 if(_str)
 {
 delete[] _str;
 _str = nullptr;
 }
 }
 
private:
 char* _str;
};

2 现代版写法的string

class string
{
public:
 string(const char* str = "")
 {
 if(nullptr == str)
 str = "";
_str = new char[strlen(str) + 1];
 strcpy(_str, str);
 }
 
 string(const string& s)
 : _str(nullptr)
 {
 string strTmp(s._str);
 swap(_str, strTmp._str);
 }
 
 // 对比下和上面的赋值那个实现比较好?
 string& operator=(string s)
 {
 swap(_str, s._str); 
 return *this;
 }
 
 /*
 string& operator=(const string& s)
 {
 if(this != &s)
 {
 string strTmp(s);
 swap(_str, strTmp._str);
 }
 
 return *this;
 }
 */
 
 ~string()
 {
 if(_str)
 {
 delete[] _str;
 _str = nullptr;
 }
 }
 
private:
 char* _str;
};

3 增

		//开空间,扩展capacity
		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strncpy(tmp, _str,_size+1);
				delete[] _str;

				_str = tmp;
				_capacity = n;
			}
		}
		//开空间并且初始化,扩展capacity,size也要动。
		void resize(size_t n,char val='\0')
		{
			if (n < _capacity)
			{
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				if (n > _capacity)
				{
					reserve(n);
					for (size_t i = _size; i < n; i++)
					{
						_str[i] = val;
					}
				}
				_str[n] = '\0';
				_size = n;
			}
		}

		//push_back
		void push_back(char ch)
		{
			//if (_size == _capacity)
			//{
			//	reserve(_capacity==0?4: _capacity * 2);
			//}
			//_str[_size] = ch;
			//_str[_size +=1] = '\0';
			insert(_size, ch);
		}
		//append
		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);
		}
		//s1+='s'
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		//s1+="string"
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
		//在pos位置之前插入字符ch
		string& insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			size_t end = _size+1; //解决头插 end会减为负数的问题
			while (end > pos)
			{
				_str[end] = _str[end-1];
				end--;
			}
			_str[pos] = ch;
			_size++;
			return *this;
		}
		//在pos位置之前插入字符串str
		string& insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			//挪动数据
			char* end = _str + _size;
			while (end >= _str + pos)
			{
				*(end + len) = *end;
				end--;
			}
			strncpy(_str+pos,str,len);
			_size += len;
			return *this;
		}

4 删

		//从pos位置开始向后删除len个字符
		string& erase(size_t pos, size_t len=npos)
		{
			assert(pos < _size);
			size_t leftLen = _size - pos;
			if (leftLen <= len)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
			return *this;
		}

5 查

		//查找
		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* str, size_t pos=0)
		{
			assert(pos<_size);
			const char* ret = strstr(_str+ pos, str);
			if (ret)
			{
				return ret - _str;
			}
			else
			{
				return npos;
			}
		}

6 改

	//只清除数据
	void clear()
	{
		_size = 0;
		_str[0] = '\0';
	}
	//>>重载,获取数据,遇到空格或者换行结束
	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char ch;
		ch=in.get();
		while (ch != ' ' && ch != '\n')
		{
			s += ch;
			ch = in.get();
		}
		return in;
	}
	//获取一行数据,遇到换行结束。
	istream& getline(istream& in, string& s)
	{
		s.clear();
		char ch;
		ch = in.get();
		while (ch != '\n')
		{
			s += ch;
			ch = in.get();
		}
		return in;
	}

7 遍历

		//遍历,为了能使用修改下标修改值,使用传引用返回。
		//at总用和operator []类似,越界是抛异常。
		//给congst对象调用,只读
		const char& operator[](size_t i) const//(修饰隐含的this)
		{
			assert(i < _size);
			return _str[i];
		}
		//给非congst对象调用,可读可写。
		char& operator[](size_t i) 
		{
			assert(i < _size);
			return _str[i];
		}
		//size
		size_t size() const
		{
			return _size;
		}

		//迭代器
		typedef char* iterator;
		typedef const char* const_iterator;
		//可读可写
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str+_size;
		}
		//只读
		const_iterator begin() const
		{
			return _str;
		}
		const_iterator end() const
		{
			return _str + _size;
		}

8 比较运算符重载

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

你可能感兴趣的:(C/C++学习笔记,c++,开发语言)