前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >【C++】深入探索string类的实现(下)(含源码)

【C++】深入探索string类的实现(下)(含源码)

作者头像
TANGLONG
发布2025-03-27 08:21:11
发布2025-03-27 08:21:11
4000
代码可运行
举报
运行总次数:0
代码可运行

该篇文章承接上一篇文章string类的实现(上),希望大家可以先看看上一篇文章,链接如下:【C++】深入探索string类的实现(上)

一、元素访问接口

    我们来看看访问接口有哪些,如下:

    这几个接口非常简单,前两个就是根据下标去取对应的字符,后面两个接口一个是取最后一个字符,一个是取第一个元素,这里我们直接给出实现了,如下:

代码语言:javascript
代码运行次数:0
运行
复制
char& operator[](size_t n)
{
	assert(n >= 0 && n < _size);
	return _str[n];
}

char& at(size_t n)
{
	assert(n >= 0 && n < _size);
	return _str[n];
}

char& front()
{
	return _str[0];
}

char& back()
{
	return _str[_size - 1];
}

const char& operator[](size_t n) const
{
	assert(n >= 0 && n < _size);
	return _str[n];
}

const char& at(size_t n) const
{
	assert(n >= 0 && n < _size);
	return _str[n];
}

const char& front() const
{
	return _str[0];
}

const char& back() const
{
	return _str[_size - 1];
}

二、迭代器实现

    string类和我们之后要讲的vector的迭代器都非常好实现,因为它们两个容器的本质都是顺序表,底层都是数组,可以直接通过指针访问数据,所以string类的迭代器其实就是指针,只是被typedef了,而list等容器的迭代器则是一个类,我们以后会讲到,string类的迭代器如下:

代码语言:javascript
代码运行次数:0
运行
复制
typedef char* iterator;
typedef const char* const_iterator;

    接下来我们来实现普通迭代器和const迭代器的begin和end,begin就是第一个元素的地址,end就是最后一个元素的下一个空间的地址,如下:

代码语言:javascript
代码运行次数:0
运行
复制
iterator begin()
{
	return _str;
}

iterator end()
{
	return _str + _size;
}

//const迭代器
const_iterator begin() const
{
	return _str;
}

//const迭代器
const_iterator end() const
{
	return _str + _size;
}

    接下来我们使用范围for来测试一下迭代器,因为范围for的底层其实就是迭代器,如下:

    可以看到范围for可以跑通,说明我们的迭代器基本没问题,如果还有疑问可以自己尝试使用迭代器的方法测试

三、有关容量的接口

    我们来看看这些接口有哪些:

    可以看到其中有些接口是比较简单的,比如size、capacity、empty、clear等等,这些我们在顺序表那里就学过了,只是其中这个clear没有学过,但是也非常简单,清空数据可以直接把size置为0,然后补上\0就可以了,上面这些函数的代码我们就直接写出来了,如下:

代码语言:javascript
代码运行次数:0
运行
复制
size_t size() const
{
	return _size;
}

size_t capacity() const
{
	return _capacity;
}

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

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

    这里我们只需要实现resize接口就可以了,因为扩容接口reserve我们已经实现过了,我们来看看它的所有接口:

    这两个接口如果n比size大都会填充字符,只是第一个字符填充\0,而第二个接口需要指定填充的字符,所以我们其实可以把这两个接口写成一个接口,其中字符c的默认值为\0就可以了,接下来我们来分析如何实现resize

    resize有三种情况我们就用if将这三种情况进行划分,如果n小于或等于原本的size,那么我们就直接将size改成n就行了,进行对应的缩容,但是不要忘了把\0添加到最后,如果n大于size但是小于等于当前的容量,那么我们就把中间的空间都填充成对应的字符,如果n大于当前容量就进行扩容,并且从size到n都填充对应的字符,如下:

代码语言:javascript
代码运行次数:0
运行
复制
void string::resize(size_t n, char c)
{
	assert(n >= 0);
	if (n <= _size)
	{
		_size = n;
		_str[_size] = '\0';
	}
	else if (n <= _capacity)
	{
		//走到这里n一定大于size,但是小于等于capacity
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = c;
		}
		_size = n;
		_str[_size] = '\0';
	}
	else
	{
		//n大于capacity,扩容
		reserve(n);
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = c;
		}
		_str[_size] = '\0';
	}
}

    上面就是resize的实现,但是我们发现有两个地方代码有一些冗余,一个地方是三个判断中我们都要将size位置的数据改为\0,我们可以把它拿出来减少冗余

    第二个地方就是第二个和第三个判断中挪动数据的逻辑一致,只是有一个没有用reserve,但是我们想想我们之前实现的reserve是不是在扩容前会进行一次判断,如果参数小于capacity就不会扩容,所以第二个判断中n大于size但是小于capacity,就算使用reserve也不会发生扩容,因为在reserve函数中作了判断,所以我们可以将第二个判断和第三个判断合并,优化后如下:

代码语言:javascript
代码运行次数:0
运行
复制
void string::resize(size_t n, char c)
{
	assert(n >= 0);
	if (n <= _size)
	{
		_size = n;
	}
	else
	{
		//如果n小于capacity不会发生扩容
		reserve(n);
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = c;
		}
		_size = n;
	}
	//都要执行这个逻辑就拿出来
	_str[_size] = '\0';
}

四、字符串操作

    我们来看看有哪些函数:

c_str

    首先第一个c_str最简单,直接返回string对象底层的数组即可,如下:

代码语言:javascript
代码运行次数:0
运行
复制
const char* c_str() const
{
	return _str;
}

find

    接下来我们来实现两个查找方法,首先是正向的find,我们来看看具体有哪些接口:

    这里我们实现两个接口,一个是查找一个字符,一个是查找string类对象,首先我们来看查找一个字符,只需要我们从pos位置开始遍历容器即可,如果查找到就返回下标,否则返回npos,如下:

代码语言:javascript
代码运行次数:0
运行
复制
size_t string::find(char c, size_t pos)
{
    //如果pos过大进入不了循环
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == c)
		{
			return i;
		}
	}
	return npos;
}

    接下来我们就来实现查找一个string对象,它的本质其实是查找这个string对象中的字符串,我们可以通过函数strstr实现,具体方法就是在遍历过程中看第一个字符是否相同,如果相同那么就通过strstr函数进行匹配,成功了就返回,失败继续查找,到最后都没有找到就返回npos,如下:

代码语言:javascript
代码运行次数:0
运行
复制
size_t string::find(const string& str, size_t pos)
{
	//如果pos过大进入不了循环
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == str[i])
		{
			char* ret = strstr(_str, str._str);
			if (ret)
			{
				return i;
			}
		}
	}
	return npos;
}

rfind

    rfind的接口和find的接口也差不多,如下:

    rfind我们也实现两个接口,一个是查找字符,一个是查找string对象,其实rfind和find的实现基本上没什么不同,只是rfind从后往前找而已,如下:

代码语言:javascript
代码运行次数:0
运行
复制
size_t string::rfind(char c, size_t pos)
{
	if (pos > _size)
		pos = _size - 1;
	for (size_t i = pos; i >= 0; i--)
	{
		if (_str[i] == c)
		{
			return i;
		}
	}
	return npos;
}

size_t string::rfind(const string& str, size_t pos)
{
	if (pos > _size)
		pos = _size - 1;
	for (size_t i = pos; i >= 0; i--)
	{
		if (_str[i] == str[0])
		{
			char* ret = strstr(_str, str._str);
			if (ret)
			{
				return i;
			}
		}
	}
	return npos;
}

substr

    substr的接口形式只有一个,就是从pos位置开始,向后截取长度为len的字符串,最后以string的形式返回,如下:

    这里我们要注意的是在截取字符串的时候是否越界,比如当len > _size + pos,这个时候就会发生越界,因为_size - pos表示当前字符串还剩多少个字符可以被截取,如果len大于了这个数量就会照成越界,此时只需让len = _size + pos即可

    解决了越界的问题我们就开始截取字符串,方法也很简单,我们用循环的方式把对应的字符插入一个新的string类对象中即可,如下:

代码语言:javascript
代码运行次数:0
运行
复制
string string::substr(size_t pos, size_t len)
{
	//pos不会小于0,因为类型为size_t
	assert(pos < _size);
	//_size - pos表示剩余的字符数,len不能大于这个数
	if (len > _size - pos)
		len = _size - pos;
	string str;
	str.reserve(len);
	for (size_t i = pos; i < pos + len; i++)
	{
		str += _str[i];
	}
	return str;
}

compare

    我们来看看compare函数的接口,如下:

    compare的底层就是封装了strcmp,我们就实现图上的第一个接口就行了,如下:

代码语言:javascript
代码运行次数:0
运行
复制
int string::compare(const string& str) const
{
	return strcmp(_str, str._str);
}

五、非成员函数重载

各种关系运算重载

    关系运算就是等于、大于、小于等运算,接下来我们来实现一下这些关系运算,只需要利用之前写的compare函数即可,如下:

代码语言:javascript
代码运行次数:0
运行
复制
bool operator==(const string& str1, const string& str2)
{
	return str1.compare(str2) == 0;
}

bool operator!=(const string& str1, const string& str2)
{
	return !(str1 == str2);
}

bool operator<(const string& str1, const string& str2)
{
	return str1.compare(str2) < 0;
}

bool operator<=(const string& str1, const string& str2)
{
	return str1 < str2 || str1 == str2;
}

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

bool operator>=(const string& str1, const string& str2)
{
	return str1 > str2 || str1 == str2;
}

流提取运算符>>重载

    流提取运算符的重载是为了方便我们输出string类对象,方法也很简单,就是把string对象的字符一个一个输出即可,如下:

代码语言:javascript
代码运行次数:0
运行
复制
ostream& operator<<(ostream& out, const string& str)
{
	for (int i = 0; i < str.size(); i++)
	{
		cout << str[i];
	}
	return out;
}

流插入运算符<<重载

    流插入运算符重载是为了方便我们给string对象手动进行输入,写这个函数要注意的地方还是挺多的,第一个注意的点是我们去读取字符的时候不能直接用cin,因为cin不会读取空格和\n,要想读取所有类型的字符就要用istream对象的成员函数get,等下我们会演示

    第二个点是我们在进行插入之前要把以前的数据清空,否则就达不到我们的预期,其实还有第三个点,但是我们可以后面说,我们先按照上面的大致思路写出代码,如下:

代码语言:javascript
代码运行次数:0
运行
复制
istream& operator>>(istream& in, string& str)
{
	//清空之前的数据
	str.clear();
	char c = in.get();
	while (c != ' ' && c != '\n')
	{
		str += c;
		c = in.get();
	}
	return in;
}

    上面的代码其实已经可以运行了,但是其实还是有一些缺点,就是效率可能不是很高,因为如果我们输入的字符串很长,那么就会反复进行扩容,所以为了提高效率我们可以设计一个缓冲区,先将数据放入这个缓冲区,等缓冲区满了再一次性写入对象,如下:

代码语言:javascript
代码运行次数:0
运行
复制
istream& operator>>(istream& in, string& str)
{
	str.clear();
	char c = in.get();
	int i = 0;
	char buff[256];
	while (c != ' ' && c != '\n')
	{
		buff[i++] = c;
		c = in.get();
		if (i == 255)
		{
			buff[i] = '\0';
			str += buff;
			i = 0;
		}
	}
	if (i > 0)
	{
		buff[i] = '\0';
		str += buff;
	}
	return in;
}

getline实现

    getline和流插入运算符重载其实很像,只是它们循环的判断条件不同,getline是根据分隔符delim来判断循环是否继续,delim的默认值是\n,如下:

代码语言:javascript
代码运行次数:0
运行
复制
istream& getline(istream& in, string& str, char delim)
{
	str.clear();
	char c = in.get();
	int i = 0;
	char buff[256];
	while (c != delim)
	{
		buff[i++] = c;
		c = in.get();
		if (i == 255)
		{
			buff[i] = '\0';
			str += buff;
			i = 0;
		}
	}
	if (i > 0)
	{
		buff[i] = '\0';
		str += buff;
	}
	return in;
}

六、源码

string.h

代码语言:javascript
代码运行次数:0
运行
复制
#pragma once
#include <iostream>
#include <cstring>
#include <cassert>
using namespace std;

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

		//构造
		string(const char* s = "");
		string(size_t n, char c);
		//现代写法需要用到swap
		void swap(string& str);
		//拷贝构造与赋值重载
		string(const string& str);
		string& operator=(const string& str);
		//析构
		~string();

		void reserve(size_t n);
		void push_back(const char c);
		void pop_back();
		void append(const string& str);
		void append(size_t n, char c);
		void insert(size_t pos, const string& str);
		void insert(size_t pos, size_t n, char c);
		void erase(size_t pos = 0, size_t len = npos);
		string& operator+=(const string& str);
		string& operator+=(char c);
		void resize(size_t n, char c = '\0');
		size_t find(char c, size_t pos = 0);
		size_t find(const string& str, size_t pos = 0);
		size_t rfind(char c, size_t pos = npos);
		size_t rfind(const string& str, size_t pos = npos);
		string substr(size_t pos = 0, size_t len = npos);
		int compare(const string& str) const;

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

		char& at(size_t n)
		{
			assert(n < _size);
			return _str[n];
		}

		char& front()
		{
			return _str[0];
		}

		char& back()
		{
			return _str[_size - 1];
		}

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

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

		const char& front() const
		{
			return _str[0];
		}

		const char& back() const
		{
			return _str[_size - 1];
		}

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		//const迭代器
		const_iterator begin() const
		{
			return _str;
		}

		//const迭代器
		const_iterator end() const
		{
			return _str + _size;
		}

		size_t size() const
		{
			return _size;
		}

		size_t capacity() const
		{
			return _capacity;
		}

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

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


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

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

	string operator+(char c, const string& str);
	string operator+(const char* s, const string& str);
	string operator+(const string& str, char c);
	string operator+(const string& str, const char* s);
	void swap(string& s1, string& s2);
	istream& getline(istream& in, string& str, char delim = '\n');
	ostream& operator<<(ostream& out, const string& str);
	istream& operator>>(istream& in, string& str);
	bool operator==(const string& str1, const string& str2);
	bool operator!=(const string& str1, const string& str2);
	bool operator<(const string& str1, const string& str2);
	bool operator<=(const string& str1, const string& str2);
	bool operator>(const string& str1, const string& str2);
	bool operator>=(const string& str1, const string& str2);

}

string.cpp

代码语言:javascript
代码运行次数:0
运行
复制
#define _CRT_SECURE_NO_WARNINGS

#include "string.h"

namespace TL
{
	const size_t string::npos = -1;

	string::string(const char* s)
		:_size(strlen(s))
	{
		_capacity = _size;
		//注意要多开一个空间存放\0
		_str = new char[_capacity + 1];
		//strcpy会拷贝\0
		strcpy(_str, s);
	}

	string::string(size_t n, char c)
		:_size(n)
	{
		_capacity = _size;
		//注意要多开一个空间存放\0
		_str = new char[_capacity + 1];
		for (size_t i = 0; i < _size; i++)
		{
			_str[i] = c;
		}
		_str[_size] = '\0';
	}

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


	string::string(const string& str)
	{
		//以前的写法
		/*if (_str)
			delete[] _str;
		_str = new char[str._capacity + 1];
		_size = str._size;
		_capacity = str._capacity;
		strcpy(_str, str._str);*/

		//现代写法(利用构造)
		string tmp(str._str);
		swap(tmp);
	}

	string& string::operator=(const string& str)
	{
		//注意判断,不要自己给自己赋值
		if (this != &str)
		{
			//普通写法
			/*if (_str)
				delete[] _str;
			_str = new char[str._capacity + 1];
			strcpy(_str, str._str);
			_size = str._size;
			_capacity = str._capacity;*/

			//利用拷贝构造,也可以利用构造
			string tmp(str);
			swap(tmp);
		}
		return *this;
	}

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

	void string::reserve(size_t n)
	{
		//如果参数小于等于容量就不予处理
		if (n <= _capacity)
		{
			return;
		}
		//2倍扩容
		size_t newCapacity = _capacity * 2;
		//如果2倍扩容不够就直接扩容到n
		if (newCapacity < n)
			newCapacity = n;
		//开新空间,注意还是要多开一个空间以后放\0用
		char* tmp = new char[newCapacity + 1];
		//数据的拷贝
		strcpy(tmp, _str);
		delete[] _str;
		_str = tmp;
		_capacity = newCapacity;
	}


	void string::push_back(char c)
	{
		//注意查看空间是否满了,如果满了就扩容
		if (_size == _capacity)
		{
			reserve(2 * _capacity);
		}
		_str[_size++] = c;
		_str[_size] = '\0';
	}

	void string::pop_back()
	{
		//确保数组不为空
		assert(_size > 0);
		//size--相当于就把它删除了
		_size--;
		//补上\0
		_str[_size] = '\0';
	}


	void string::append(const string& str)
	{
		size_t len = strlen(str._str);
		if (len + _size > _capacity)
		{
			reserve(len + _size);
		}
		//将str的字符串拷贝到当前对象
		//注意\0会跟着一起拷贝,不需要专门给
		strcpy(_str + _size, str._str);
		_size += len;
	}

	void string::append(size_t n, char c)
	{
		if (n + _size > _capacity)
		{
			reserve(n + _size);
		}
		for (size_t i = _size; i < n + _size; i++)
		{
			_str[i] = c;
		}
		_size += n;
		_str[_size] = '\0';
	}

	void string::insert(size_t pos, const string& str)
	{
		assert(pos <= _size);
		size_t len = strlen(str._str);
		if (_size + len > _capacity)
		{
			reserve(_size + len);
		}
		size_t src = _size - 1;
		size_t dest = src + len;
		//这里如果不强转为int就会导致死循环和越界访问
		//因为src类型是size_t,pos为0再--会变成非常大的数
		while ((int)src >= (int)pos)
		{
			_str[dest--] = _str[src--];
		}
		//下面这句strcpy也能实现上面的拷贝功能
		//strcpy(_str + pos + len, _str + pos);
		/*dest = pos;
		for (size_t i = 0; i < str._size; i++)
		{
			_str[dest++] = str._str[i];
		}*/
		//不拷贝\0
		strncpy(_str + pos, str._str, strlen(str._str));
		_size += len;
		_str[_size] = '\0';
	}

	void string::insert(size_t pos, size_t n, char c)
	{
		assert(pos <= _size);
		if (_size + n > _capacity)
		{
			reserve(_size + n);
		}
		size_t src = _size - 1;
		size_t dest = src + n;
		while ((int)src >= (int)pos)
		{
			_str[dest--] = _str[src--];
		}
		//循环填充字符
		for (size_t i = pos; i < pos + n; i++)
		{
			_str[i] = c;
		}
		_size += n;
		_str[_size] = '\0';
	}

	void string::erase(size_t pos, size_t len)
	{
		assert(pos < _size);
		if (len > _size - pos)
			len = _size - pos; 
		size_t src = pos + len;
 		size_t dest = pos;
		/*for (size_t i = pos + len; i < _size; i++)
		{
			_str[dest++] = _str[src++];
		}*/
		while (src < _size)
		{
			_str[dest++] = _str[src++];
		}
		//下面这句strcpy也可以实现数据的覆盖拷贝,达到删除的目的
		//strcpy(_str + pos, _str + pos + len);
		_size -= len;
		_str[_size] = '\0';
	}

	//void string::resize(size_t n, char c)
	//{
	//	assert(n >= 0);
	//	if (n <= _size)
	//	{
	//		_size = n;
	//		_str[_size] = '\0';
	//	}
	//	else if (n <= _capacity)
	//	{
	//		//走到这里n一定大于size,但是小于等于capacity
	//		for (size_t i = _size; i < n; i++)
	//		{
	//			_str[i] = c;
	//		}
	//		_size = n;
	//		_str[_size] = '\0';
	//	}
	//	else
	//	{
	//		//n大于capacity,扩容
	//		reserve(n);
	//		for (size_t i = _size; i < n; i++)
	//		{
	//			_str[i] = c;
	//		}
	//		_str[_size] = '\0';
	//	}
	//}

	void string::resize(size_t n, char c)
	{
		if (n <= _size)
		{
			_size = n;
		}
		else
		{
			//如果n小于capacity不会发生扩容
			reserve(n);
			for (size_t i = _size; i < n; i++)
			{
				_str[i] = c;
			}
			_size = n;
		}
		//都要执行这个逻辑就拿出来
		_str[_size] = '\0';
	}

	

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

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

	//不是成员函数
	string operator+(char c, const string& str)
	{
		//之前实现的n个c字符的构造
		string tmp(1, c);
		//直接复用+=
		return tmp += str;
	}

	string operator+(const char* s, const string& str)
	{
		//字符串的构造
		string tmp(s);
		//复用+=
		return tmp += str;
	}

	string operator+(const string& str, char c)
	{
		string tmp(str);
		//利用匿名对象
		return tmp += string(1, c);
	}

	string operator+(const string& str, const char* s)
	{
		string tmp(str);
		//利用隐式类型转换,将s转换为string然后+=
		return tmp += s;
	}

	void swap(string& s1, string& s2)
	{
		s1.swap(s2);
	}

	size_t string::find(char c, size_t pos)
	{
		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == c)
			{
				return i;
			}
		}
		return npos;
	}

	size_t string::find(const string& str, size_t pos)
	{
		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == str[i])
			{
				char* ret = strstr(_str, str._str);
				if (ret)
				{
					return i;
				}
			}
		}
		return npos;
	}

	size_t string::rfind(char c, size_t pos)
	{
		if (pos > _size)
			pos = _size - 1;
		for (size_t i = pos; i >= 0; i--)
		{
			if (_str[i] == c)
			{
				return i;
			}
		}
		return npos;
	}

	size_t string::rfind(const string& str, size_t pos)
	{
		if (pos > _size)
			pos = _size - 1;
		for (size_t i = pos; i >= 0; i--)
		{
			if (_str[i] == str[0])
			{
				char* ret = strstr(_str, str._str);
				if (ret)
				{
					return i;
				}
			}
		}
		return npos;
	}

	string string::substr(size_t pos, size_t len)
	{
		//pos不会小于0,因为类型为size_t
		assert(pos < _size);
		//_size - pos表示剩余的字符数,len不能大于这个数
		if (len > _size - pos)
			len = _size - pos;
		string str;
		str.reserve(len);
		for (size_t i = pos; i < pos + len; i++)
		{
			str += _str[i];
		}
		return str;
	}

	int string::compare(const string& str) const
	{
		return strcmp(_str, str._str);
	}

	istream& getline(istream& in, string& str, char delim)
	{
		str.clear();
		char c = in.get();
		int i = 0;
		char buff[256];
		while (c != delim)
		{
			buff[i++] = c;
			c = in.get();
			if (i == 255)
			{
				buff[i] = '\0';
				str += buff;
				i = 0;
			}
		}
		if (i > 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return in;
	}

	ostream& operator<<(ostream& out, const string& str)
	{
		for (int i = 0; i < str.size(); i++)
		{
			cout << str[i];
		}
		return out;
	}

	istream& operator>>(istream& in, string& str)
	{
		str.clear();
		char c = in.get();
		int i = 0;
		char buff[256];
		while (c != ' ' && c != '\n')
		{
			buff[i++] = c;
			c = in.get();
			if (i == 255)
			{
				buff[i] = '\0';
				str += buff;
				i = 0;
			}
		}
		if (i > 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return in;
	}

	bool operator==(const string& str1, const string& str2)
	{
		return str1.compare(str2) == 0;
	}

	bool operator!=(const string& str1, const string& str2)
	{
		return !(str1 == str2);
	}

	bool operator<(const string& str1, const string& str2)
	{
		return str1.compare(str2) < 0;
	}

	bool operator<=(const string& str1, const string& str2)
	{
		return str1 < str2 || str1 == str2;
	}

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

	bool operator>=(const string& str1, const string& str2)
	{
		return str1 > str2 || str1 == str2;
	}

}

    那么到这里string类的实现我们就讲完了,是不是对string有了新的理解呢?下一篇文章我们就开始学习vector了,敬请期待吧!     bye~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-03-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、元素访问接口
  • 二、迭代器实现
  • 三、有关容量的接口
  • 四、字符串操作
    • c_str
    • find
    • rfind
    • substr
    • compare
  • 五、非成员函数重载
    • 各种关系运算重载
    • 流提取运算符>>重载
    • 流插入运算符<<重载
    • getline实现
  • 六、源码
    • string.h
    • string.cpp
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档