Gitee仓库:

拂拉氏/my_string


目录

前言:

Part1. 默认成员函数

Part1.1 拷贝构造函数

Part1.2 赋值重载函数

Part2. 简单函数

Part3. 复杂函数

Part3.1 C语言隐弊之隐式类型转换

Part3.2 KMP算法实现

Part3.3 哈希思想的应用

Part4. 运算符重载相关函数

Part5. 代码分享

Part5.1 源1.cpp

Part5.2 头.h

Part6. 结语


前言:

  C++标准库string类作为STL的重要组成部分,我们了解他是必要的,而我们了解这个的最好方式就是亲自去实现它。接下来,让我们来看一下吧:


let's go!!!!!


Part1. 默认成员函数

  默认成员函数作为类成员函数中必不可少的一环,自然是我们首当其冲就要实现的存在,我们来看代码:

public:
    string(const char* str="")//缺省构造函数
	    :_capacity(strlen(str))//初始化列表为_capacity,_size初始化
	    ,_size(strlen(str))
    {
	    _str=new char[strlen(str) + 1];//为其分配初始空间
	    strcpy(_str, str);
	    _str[size()] = '\0';//一定要注意\0!! 要不然后续打印没有终止信号 会有乱码出现
    }

    string(const string& s)//拷贝构造函数
    {
	    string tem(s._str);//下面结合图来解释
	    swap(tem);
    }

    ~string()//析构函数
    {
	    if (_str != nullptr)//当_str为nullptr不析构
	    {
	    	delete[] _str;
	    	_str = nullptr;
	    	_capacity = 0;
	    	_size = 0;
	    }
    }

    void operator=(string s)//赋值重载函数
    {
    	swap(s);//下面结合图来解释
    }

    void swap(string& s)//实现交换(可以认为为浅拷贝)
    {
	    std::swap(_str, s._str);
	    std::swap(_capacity, s._capacity);
	    std::swap(_size, s._size);
    }
private:
	char* _str=nullptr;//初始化为nullptr
	size_t _capacity;
	size_t _size;
	static const size_t npos=-1;//缺省值

  上面的四个默认成员函数值得注意的就是拷贝构造赋值重载函数,这两个函数都以较短的语句实现了应有的效果,但其的含义却很深,我们来结合图来看一下是怎么做到的吧:


Part1.1 拷贝构造函数


  上面的图解释了拷贝构造的来龙去脉,以及为什么要初始化每个_str为nullptr的原因,关键还是在于我们复用了析构和构造函数的代码。接下来,让我们来看看赋值重载吧:


Part1.2 赋值重载函数

  上面的图解释了赋值重载这样写的由来,关键还是与上面一样,就是代码的复用


  但这时候,可能会有人会疑惑。为什么上面拷贝构造不这样呢?因为拷贝构造只能传引用类型,不然会无穷递归,同时我们要保证我们的S(拷贝过去的对象)不被改变,就只能利用一个临时变量来承接了。


  这样,我们就完成了默认成员函数的介绍。接下来,我们来看看string类简单函数的模拟实现吧:


Part2. 简单函数

  简单函数,人如其名自然是实现比较简单的,我们来看代码:

public:
typedef  char* iterator;//迭代器的简单实现 把他认作char*
typedef const char* const_iterator;//常性迭代器同理

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

void swap(string& s)//交换
{
	std::swap(_str, s._str);
	std::swap(_capacity, s._capacity);
	std::swap(_size, s._size);
}
iterator begin()//返回迭代器的开始
{
	return _str;
}
iterator end()//返回结束
{
	return _str + size();
}
const_iterator begin()const
{
	return _str;
}
const_iterator end()const
{
	return _str + size();
}
void clear()//删光数据 不改容量(_capacity)
{
	_str[0] = '\0';
	_size = 0;
}

  上文的函数介绍就不需要了,关键在于我们为什么能用typedef来直接模拟迭代器?因为迭代器的一些作用与原生指针非常相似,在string类这里尤其是。因此我们可以用char*来简单模拟迭代器,为后面的范围for遍历做准备。

  这样简单函数就实现了,这些都是为后面的一些较复杂的函数做准备的,我们来看看吧:


Part3. 复杂函数

  复杂函数关键是要在意边界条件的控制,还有的函数(find)要利用我们自己实现的工具函数来辅助实现,我们来看:

public://函数声明
string& operator+=(char ch);
string& operator+=(const char* str);
void reserve(size_t n);
void push_back(char ch);
void append(const char* str);
bool empty()const;
void insert(size_t pos, char ch);
void insert(size_t pos, const char* str);
void erase(size_t pos,size_t len=npos);
size_t find(char ch, size_t pos=0)const;
size_t find(const char* str, size_t pos = 0)const;
size_t find_first_of(const char* str,size_t pos=0)const;
size_t find_not_of(const char* str, size_t pos = 0)const;
void replace(size_t pos, const char* str,const size_t n = npos);
char* c_str()const;
string substr(size_t pos=0, size_t n=npos);


//函数实现
string& string::operator+=(char ch)//+=运算符重载(用于单个字符)
{
	assert(ch);//加上assert 代码健壮性
	push_back(ch);
	return *this;
}

string& string::operator+=(const char* str)//+=运算符重载(用于字符串)
{
	assert(str);
	append(str);
	return *this;
}

void string::reserve(size_t n)//开拓空间函数
{
	char* tem = new char[n];//利用临时变量承接
	strcpy(tem, _str);
	std::swap(tem, _str);
	delete[] tem;
	_capacity = n;
}

void string::push_back(char ch)//往后放一个字符
{
	assert(ch);
	if (_size + 1 >= _capacity)//判断开多少空间
	{
		2 * _capacity > _size + 2 ? reserve(2 * _capacity) : reserve(_size + 2);
	}
	_str[_size] = ch;
	_size++;
	_str[_size] = '\0';//时刻注意\0
}

void string::append(const char* str)//往后接一个字符串
{
	assert(str);
	if (str == "")
	{
		return;
	}
	if (_size + strlen(str) >= _capacity)
	{
		2 * _capacity > _size + strlen(str) + 1 ? reserve(2 * _capacity) : reserve(_size + strlen(str) + 1);
	}
	for (size_t i = size(); i <= _size + strlen(str); i++)//放入数据 连带着\0也会拷贝过去
	{
		_str[i] = str[i - size()];
	}
	_size += strlen(str);
}

void string::insert(size_t pos, char ch)//在pos前插入单个字符
{
	assert(ch && pos >= 0 && pos <= size());
	size_t i = 0;
	if (_size + 1 >= _capacity)
	{
		2 * _capacity > _size + 2 ? reserve(2 * _capacity) : reserve(_size + 2);
	}
	for (i = size(); i > pos; i--)//移动原先字符串 为要来的字符挪开位置
	{
		_str[i + 1] = _str[i];
	}
	_str[i + 1] = _str[i];// <1>
	_str[pos] = ch;
	_size += 1;
}

void string::insert(size_t pos, const char* str)//与上面一致
{
	assert(str && pos >= 0 && pos <= size());
	size_t i = 0;
	size_t len = strlen(str);
	if (_size + len >= _capacity)
	{
		2 * _capacity > _size + len + 1 ? reserve(2 * _capacity) : reserve(_size + len + 1);
	}
	for (i = size(); i > pos; i--)
	{
		_str[i + len] = _str[i];
	}
	_str[i + len] = _str[i];
	for (i = pos; i < pos + len; i++)
	{
		_str[i] = str[i - pos];
	}
	_size += len;
}

void string::erase(size_t pos, size_t len)//删除pos后len个字符
{
	assert(len >= 0 && pos >= 0 && pos < size());
	if (len == 0)
	{
		return;
	}
	if (len == -1 || pos + len - 1 >= size())//如果len太大 修正一下
	{
		len = size() - pos;
	}
	for (size_t i = pos + len; i <= size(); i++)//后面的数据往前覆盖 包括\0
	{
		_str[i - len] = _str[i];
	}
	_size -= len;
}

size_t string::find(char ch, size_t pos)const//找单个字符 找到返回其位置
{
	assert(ch && pos >= 0);
	for (int i = 0; i < size(); i++)
	{
		if (_str[i] == ch)
		{
			return i;
		}
	}
	return npos;
}

size_t string::find(const char* str, size_t pos)const//找字符串 找到返回其首位置
{
	assert(str);
	return all::tool::kmp_find(_str, str);// <2>
}

size_t string::find_first_of(const char* str, size_t pos)const//若找到任意的存在于_str中的字符返回其位置
{
	assert(str&&pos>=0);
	short buf[256] = { 0 };// <3>
	size_t n = strlen(str);
	for (int i = 0; i < n; i++)
	{
		buf[str[i]] = -1;
	}
	for (int i = 0; i < _size; i++)
	{
		if (buf[_str[i]] == -1)
		{
			return i;
		}
	}
	return -1;
}

size_t string::find_not_of(const char* str, size_t pos)const//若找到任意的不存在于_str中的字符返回其位置
{
	assert(str && pos >= 0);
	short buf[256] = { 0 };
	size_t n = strlen(str);
	for (int i = 0; i < n; i++)
	{
		buf[str[i]] = -1;
	}
	for (int i = 0; i < _size; i++)
	{
		if (buf[_str[i]] != -1)
		{
			return i;
		}
	}
	return -1;
}

bool string::empty()const//判空
{
	return (_size == 0);
}

void string::replace(size_t pos, const char* str, const size_t n )//将pos位置开始的n个字符取代为str
{
	assert(pos >= 0 && pos < size() && n >= 0 && str);
	erase(pos, n);
	insert(pos, str);
}

char* string::c_str()const//返回_str指针
{
	return _str;
}

string string::substr(size_t pos, size_t n)//将pos位置开始的n个字符转化为string类的形式返回
{
	assert(pos >= 0 && pos < size() && n >= 0);
	if (pos + n - 1 >= size())
	{
		n = size() - pos;
	}
	string tem;
	tem.reserve(n);
	for (int i = 0; i < n; i++)
	{
		tem += _str[i + pos];
	}
	return tem;
}

  上面我们通过代码的注释基本了解了这几个复杂函数,但仍有部分问题没有解决(上面注释标<1><2><3>的地方)。接下来,我们来逐一攻破一下吧:


Part3.1 C语言隐弊之隐式类型转换

for (i = size(); i >= pos; i--)

  我们来看上面的这个代码,当 i > pos时循环就会继续进行。当pos=0时,这个i要到 -1 才可以结束循环,但是我们这个 i 是size_t(无符号整型),它不存在负数这个概念,当它为负数的时候会自动转化为最大的整形,从而导致循环无法结束。

  这时候我们可能会想到一个方法:那就是我们把这个 i 类型改为 int 不就好了。但是坑的点就在这里,当 int 和 size_t 进行比较时,会进行隐式类型转换,将 int 转化为 size_t 从而解决不了问题。因此我们采用了这个方法:


for (i = size(); i > pos; i--)
	{
		_str[i + 1] = _str[i];
	}
	_str[i + 1] = _str[i];//将最后一步单拿出来进行 而不在循环之中

  这样我们就解决了这个问题,这个问题属于是C语言留给C++的“坑”了。


Part3.2 KMP算法实现

  KMP算法相信大家或多或少的都听说过,作为秒杀暴力字符串匹配算法的存在,我们有必要来理解一下其深邃的思想,我们来看一下吧:

	size_t tool::kmp_find(const char* _str, const char* str)//由于和string类没什么关联 故放到tool命名空间里面
	{
		int* next = new int[strlen(str) + 1];//定义移动表
		made_next(str, next);//填充
		int _p = 0;//主字符移动指针
		int p = 0;//要匹配的字符移动指针
		while (_p < strlen(_str))//开始匹配
		{
			if (_str[_p] == str[p])
			{
				_p++;
				p++;
				if (p == strlen(str))//匹配成功 返回第一个匹配成功的字符的位置
				{
					delete[] next;
					return _p - strlen(str);
				}
			}
			else
			{
				p = next[p];//失败则回溯匹配
				if (p == -1)//若回溯到开头的位置 就从头开始匹配
				{
					p = 0;
					_p++;
				}
			}
		}
		delete[] next;
		return -1;//没找到
	}

	void tool::made_next(const char* str, int* next)
	{
		next[0] = -1;//第一个固定为-1
		int left = -1;//left作用:给next[right] 同时失败时回溯
		int right = 0;//right作用:不断前进 给所在位置的next赋值
		while (right < strlen(str))
		{
			if (left == -1 || str[left] == str[right])//当left==-1或者匹配成功了left和right分别++ 并且赋值
			{
				left++;
				right++;
				next[right] = left;
			}
			else
			{
				left = next[left];//回溯
			}
		}
	}

  光看这个代码和注释估计是不好完全理解的,我们来结合图来看一下:



    我们来看上图:假如这是一个字符串,且A区和C区完全相等,假如我们用这个来匹配,且这时候D处没匹配成功,这时候怎么办?我们可以让指针到E来,因为A与C完全相等,我们前面匹配完了C区域,这时候相当于是让A取代已经匹配过的位置,减少匹配次数


  这时候我们就知道了next表中的数字的含义:

  “对于next表中x位置的值,其指代的是从0到x-1位置最多对称的字符的数目”


  所谓的填充next表的过程就是不断找对称的过程,包括回溯也是,我们来看:

  假如我们D与E匹配失败,这时候其实是延续A与C这两个大块的对称,现在不行了,我们就要找下一个对称,我们访问E的next值,找到它前面的对称(F前面),这时候相当于是将D与F前面的那个字符比较,延续F的对称了。(因为A=C -> G=H 又因为F=G -> F=H依旧对称

  这样我们就了解了KMP算法,接下来自己实践一下,彻底掌握吧!


Part3.3 哈希思想的应用

  这里说这个哈希,大家估计很陌生,但要讲计数排序大家估计就会有一点熟悉,这个是利用数组下标天然有序的性质,将值映射下标。具体的可以看我另一个博客:


八种常见排序的详细介绍和测试比较适用范围(总集篇)-CSDN博客


  我们这里利用的是字符的ASCII码值,例如‘a’的ASCII码值为97,我们就在创建的数组的第97位标记一下,标为-1啥的都行,代表这个位置的字符有过。

  这就是哈希思想,它将查找从O(N)降到了O(1)的级别,是一项伟大的突破。它在一些算法题也常有体现,是非常重要的思想。


Part4. 运算符重载相关函数

  运算符重载函数还是比较特别的。由于C++类函数第一个参数必须为隐式的*this,限制了左操作的类型,这就导致一些运算符重载必须要“游离”在成员函数之外,成为独立的存在。我们来看一下吧:

//函数声明
    std::ostream& operator<<(std::ostream& out, const string& s);
	std::istream& operator>>(std::istream& in, string& s);
    bool operator>(const string& s1, const string& s2);
	bool operator>=(const string& s1, const string& s2);
	bool operator<(const string& s1, const string& s2);
	bool operator<=(const string& s1, const string& s2);
	bool operator==(const string& s1, const string& s2);
	bool operator!=(const string& s1, const string& s2);

//函数实现
	std::ostream& operator<<(std::ostream& out, const string& s)//打印
	{
		for (auto ch : s)//范围for 包装迭代器
		{
			out << ch;
		}
		return out;
	}

	std::istream& operator>>(std::istream& in, string& s)//输入
	{
		s.clear();
		char ch;
		ch = in.get();//获得单个字符 不可用<< 这个遇到‘ ’和‘\n’会直接跳过 而不终止
		const int n = 256;
		char buf[n];//利用一个可以存256字符的数组 等到其满了再输入进_str 避免多次扩容带来的时间消耗
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buf[i++] = ch;
			if (i == n - 1)
			{
				buf[i] = '\0';
				s += buf;
				i = 0;
			}
			ch = in.get();
		}
		if (i != 0)//补充残余
		{
			buf[i] = '\0';//记得\0
			s += buf;
		}
		return in;
	}

	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 >= s2);
	}

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

	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);
	}

  运算符重载函数还是比较easy的,除了<<要特别关注一下,要用in.get()外,其余都是洒洒水啦。


Part5. 代码分享

Part5.1 源1.cpp

#include"头.h"

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

	std::istream& operator>>(std::istream& in, string& s)
	{
		s.clear();
		char ch;
		ch = in.get();
		const int n = 256;
		char buf[n];
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buf[i++] = ch;
			if (i == n - 1)
			{
				buf[i] = '\0';
				s += buf;
				i = 0;
			}
			ch = in.get();
		}
		if (i != 0)
		{
			buf[i] = '\0';
			s += buf;
		}
		return in;
	}

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

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

	void string::reserve(size_t n)
	{
		char* tem = new char[n];
		strcpy(tem, _str);
		std::swap(tem, _str);
		delete[] tem;
		_capacity = n;
	}

	void string::push_back(char ch)
	{
		assert(ch);
		if (_size + 1 >= _capacity)
		{
			2 * _capacity > _size + 2 ? reserve(2 * _capacity) : reserve(_size + 2);
		}
		_str[_size] = ch;
		_size++;
		_str[_size] = '\0';
	}

	void string::append(const char* str)
	{
		assert(str);
		if (str == "")
		{
			return;
		}
		if (_size + strlen(str) >= _capacity)
		{
			2 * _capacity > _size + strlen(str) + 1 ? reserve(2 * _capacity) : reserve(_size + strlen(str) + 1);
		}
		for (size_t i = size(); i <= _size + strlen(str); i++)
		{
			_str[i] = str[i - size()];
		}
		_size += strlen(str);
	}

	void string::insert(size_t pos, char ch)
	{
		assert(ch && pos >= 0 && pos <= size());
		size_t i = 0;
		if (_size + 1 >= _capacity)
		{
			2 * _capacity > _size + 2 ? reserve(2 * _capacity) : reserve(_size + 2);
		}
		for (i = size(); i > pos; i--)
		{
			_str[i + 1] = _str[i];
		}
		_str[i + 1] = _str[i];
		_str[pos] = ch;
		_size += 1;
	}

	void string::insert(size_t pos, const char* str)
	{
		assert(str && pos >= 0 && pos <= size());
		size_t i = 0;
		size_t len = strlen(str);
		if (_size + len >= _capacity)
		{
			2 * _capacity > _size + len + 1 ? reserve(2 * _capacity) : reserve(_size + len + 1);
		}
		for (i = size(); i > pos; i--)
		{
			_str[i + len] = _str[i];
		}
		_str[i + len] = _str[i];
		for (i = pos; i < pos + len; i++)
		{
			_str[i] = str[i - pos];
		}
		_size += len;
	}

	void string::erase(size_t pos, size_t len)
	{
		assert(len >= 0 && pos >= 0 && pos < size());
		if (len == 0)
		{
			return;
		}
		if (len == -1 || pos + len - 1 >= size())
		{
			len = size() - pos;
		}
		for (size_t i = pos + len; i <= size(); i++)
		{
			_str[i - len] = _str[i];
		}
		_size -= len;
	}

	size_t string::find(char ch, size_t pos)const
	{
		assert(ch && pos >= 0);
		for (int i = 0; i < size(); i++)
		{
			if (_str[i] == ch)
			{
				return i;
			}
		}
		return npos;
	}

	size_t string::find(const char* str, size_t pos)const
	{
		assert(str);
		return all::tool::kmp_find(_str, str);
	}

	size_t tool::kmp_find(const char* _str, const char* str)
	{
		int* next = new int[strlen(str) + 1];
		made_next(str, next);
		int _p = 0;
		int p = 0;
		while (_p < strlen(_str))
		{
			if (_str[_p] == str[p])
			{
				_p++;
				p++;
				if (p == strlen(str))
				{
					delete[] next;
					return _p - strlen(str);
				}
			}
			else
			{
				p = next[p];
				if (p == -1)
				{
					p = 0;
					_p++;
				}
			}
		}
		delete[] next;
		return -1;
	}

	void tool::made_next(const char* str, int* next)
	{
		next[0] = -1;
		int left = -1;
		int right = 0;
		while (right < strlen(str))
		{
			if (left == -1 || str[left] == str[right])
			{
				left++;
				right++;
				next[right] = left;
			}
			else
			{
				left = next[left];
			}
		}
	}

	size_t string::find_first_of(const char* str, size_t pos)const
	{
		assert(str&&pos>=0);
		short buf[256] = { 0 };
		size_t n = strlen(str);
		for (int i = 0; i < n; i++)
		{
			buf[str[i]] = -1;
		}
		for (int i = 0; i < _size; i++)
		{
			if (buf[_str[i]] == -1)
			{
				return i;
			}
		}
		return -1;
	}

	size_t string::find_not_of(const char* str, size_t pos)const
	{
		assert(str && pos >= 0);
		short buf[256] = { 0 };
		size_t n = strlen(str);
		for (int i = 0; i < n; i++)
		{
			buf[str[i]] = -1;
		}
		for (int i = 0; i < _size; i++)
		{
			if (buf[_str[i]] != -1)
			{
				return i;
			}
		}
		return -1;
	}

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

	void string::replace(size_t pos, const char* str, const size_t n )
	{
		assert(pos >= 0 && pos < size() && n >= 0 && str);
		erase(pos, n);
		insert(pos, str);
	}

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

	string string::substr(size_t pos, size_t n)
	{
		assert(pos >= 0 && pos < size() && n >= 0);
		if (pos + n - 1 >= size())
		{
			n = size() - pos;
		}
		string tem;
		tem.reserve(n);
		for (int i = 0; i < n; i++)
		{
			tem += _str[i + pos];
		}
		return tem;
	}

	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 >= s2);
	}

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

	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);
	}

}

Part5.2 头.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once

#include<iostream>
#include<algorithm>
#include<assert.h>


namespace all
{
	namespace tool
	{
		size_t kmp_find(const char* _str, const char* str);
		void made_next(const char* str, int* next);
	}

	class string
	{
	public:
		typedef  char* iterator;
		typedef const char* const_iterator;

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

		string(const string& s)
		{
			string tem(s._str);
			swap(tem);
		}

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

		void operator=(string s)
		{
			swap(s);
		}

		size_t size()const
		{
			return _size;
		}

		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_capacity, s._capacity);
			std::swap(_size, s._size);
		}
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + size();
		}
		const_iterator begin()const
		{
			return _str;
		}
		const_iterator end()const
		{
			return _str + size();
		}
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
		string& operator+=(char ch);
		string& operator+=(const char* str);
		void reserve(size_t n);
		void push_back(char ch);
		void append(const char* str);
		bool empty()const;
		void insert(size_t pos, char ch);
		void insert(size_t pos, const char* str);
		void erase(size_t pos,size_t len=npos);
		size_t find(char ch, size_t pos=0)const;
		size_t find(const char* str, size_t pos = 0)const;
		size_t find_first_of(const char* str,size_t pos=0)const;
		size_t find_not_of(const char* str, size_t pos = 0)const;
		void replace(size_t pos, const char* str,const size_t n = npos);
		char* c_str()const;
		string substr(size_t pos=0, size_t n=npos);
	private:
		char* _str=nullptr;
		size_t _capacity;
		size_t _size;
		static const size_t npos=-1;
	};
	std::ostream& operator<<(std::ostream& out, const string& s);
	std::istream& operator>>(std::istream& in, string& s);
    bool operator>(const string& s1, const string& s2);
	bool operator>=(const string& s1, const string& s2);
	bool operator<(const string& s1, const string& s2);
	bool operator<=(const string& s1, const string& s2);
	bool operator==(const string& s1, const string& s2);
	bool operator!=(const string& s1, const string& s2);

}

Part6. 结语

  我们实现了这么多的函数。利用了哈希思想,KMP算法等的手段,还发现了一些比较细节的点。但代码不止这些实现,我们还要在意安全性,例如我们利用const修饰不可改变的字符串,用assert排除显式的错误等等,这些也都是我们要注意的地方。

  希望这篇博客可以带给你们以帮助。

 最后,祝大家可以:春风得意马蹄疾,一日看尽长安花!

 最后的最后,要是觉得本文还可以的话,可以点点赞,关注小编一波,谢谢大家!~

Logo

一站式 AI 云服务平台

更多推荐