【C++】string的模拟实现

string的模拟实现

  • 1.string类的常用接口
    • [1.1 string类对象的常用构造](#1.1 string类对象的常用构造)
    • [1.2 string类对象的容量操作](#1.2 string类对象的容量操作)
    • [1.3 string类对象的访问及遍历操作](#1.3 string类对象的访问及遍历操作)
    • [1.4 string类对象的修改操作](#1.4 string类对象的修改操作)
    • [1.5 string类非成员函数](#1.5 string类非成员函数)
  • 2.模拟实现
    • [2.1 构造](#2.1 构造)
    • [2.2 容量](#2.2 容量)
    • [2.3 遍历操作](#2.3 遍历操作)
    • [2.4 修改操作](#2.4 修改操作)
    • [2.5 非成员函数](#2.5 非成员函数)
    • [2.6 swap和运算符重载](#2.6 swap和运算符重载)

1.string类的常用接口

1.1 string类对象的常用构造

(constructor)函数名称 功能说明
string() 构造空的string类对象,即空字符串
string(const char* s) 用C-string来构造string类对象
string(size_t n , char c) string类对象包含n个字符c
string(const string& s) 拷贝构造函数

1.2 string类对象的容量操作

函数名称 功能说明
size 返回字符串有效字符长度
length 返回字符串有效字符长度
capacity 返回空间总大小
empty 检测字符串释放为空串,是返回true,否则返回false
clear 清空有效字符
reserve 为字符串预留空间
resize 将有效字符串的个数改成n个,多出的空间用字符c填充

1.3 string类对象的访问及遍历操作

函数名称 功能说明
operator[] 返回pos位置的字符,const string类对象调用
begin + end beign获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
rbegin + rend rbegin获取最后一个字符的迭代器 + rend获取第一个字符上一个位置的迭代器
范围for C++11支持更简洁的范围for的新遍历方式

1.4 string类对象的修改操作

函数名称 功能说明
push_back 在字符串后尾插字符c
append 在字符串后追加一个字符串
operator+= 在字符串后追加字符串str
c_str 返回C格式字符串
find + npos 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr 在str中从pos位置开始,截取n个字符,往后将其返回

1.5 string类非成员函数

函数名称 功能说明
operator+ 尽量少用,因为传值返回,导致深拷贝效率低
operator>> 输入运算符重载
operator<< 输出运算符重载
getline 获取一行字符串
relational operators 大小比较

2.模拟实现

cpp 复制代码
#include<iostream>
#include <assert.h>
using namespace std;

class string
{
private:
	char* _str;
	size_t _size;
	size_t _capacity;
};

2.1 构造

cpp 复制代码
string()
{
	_str = new char[1] {'\0'};
	_size = 0;
	_capacity = 0;
}

string(const char* s)
{
	_str = new char[strlen(s) + 1];
	_size = _capacity = strlen(s);
	strcpy(_str, s);
}

string(size_t n, char c)
{
	_str = new char[n + 1];
	for(int i = 0;i<n;i++)
	{
		_str[i] = c;
	}
	_size = n;
	_str[n] = '\0';
}

string(const string& s)
{
	_str = new char[s._capacity + 1];
	strcpy(_str, s._str);
	_size = s._size;
	_capacity = s._capacity;
}

其中string()和string(const char* s)这两个构造可以写成全缺省

cpp 复制代码
string(const char* s = "");//声明
string(const char* s)//定义,不用给缺省值
{
	_str = new char[strlen(s) + 1];
	_size = _capacity = strlen(s);
	strcpy(_str, s);
}

2.2 容量

cpp 复制代码
size_t size() const
{
	return _size;
}

size_t length() const
{
	return _size;
}

size_t capacity() const
{
	return _capacity;
}

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

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

void reserve(size_t n)
{
	if (n > _capacity)
	{
		char* tmp = new char[n+1];
		strcpy(tmp, _str);
		delete[] _str;
		_str = tmp;
		_capacity = n;
	}
}

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

2.3 遍历操作

cpp 复制代码
char& operator[](size_t pos)
{
	assert(pos < _size);
	return _str[pos];
}
	
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();
}

2.4 修改操作

cpp 复制代码
void push_back(char ch)
{
	if (_capacity == _size)
	{
		size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
		reserve(newcapacity);
	}
	_str[_size] = ch;
	_str[_size + 1] = '\0';
	++_size;
}

void append(const char* str)
{
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		reserve(_size + len);
	}
	strcpy(_str + _size, str);
	_size += len;
}

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

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

//find实现两个,一个查找字符,一个查找字符串
size_t find(char ch, size_t pos)
{
	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)
{
	const char* p = strstr(_str + pos,  sub);
	return p - _str;
}

string substr(size_t pos, size_t len)
{
	if (len > _size - pos)
	{
		string sub(_str + pos);
		return sub;
	}
	else
	{
		string sub;
		sub.reserve(len);
		for (size_t i = 0; i < len; i++)
		{
			sub += _str[pos + i];
		}
		return sub;
	}
}

2.5 非成员函数

cpp 复制代码
//声明
istream& operator>>(istream& is, qbb::string& str);
ostream& operator<<(ostream& out, const string& s);

//定义
istream& operator>>(istream& is, string& str)
{
	str.clear();
	char buff[128];
	int i = 0;
	char ch = is.get();
	
	while (ch != ' ' && ch != '\n')
	{
		buff[i++] = ch;
		if (i == 127)
		{
			buff[i] = '\0';
			str += buff;
			i = 0;
		}
		ch = is.get();
	}
	if (i != 0)
	{
		buff[i] = '\0';
		str += buff;
	}
	return is;
}

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

2.6 swap和运算符重载

cpp 复制代码
void swap(string& s)
{
	std::swap(_str, s._str);//交换指针,本质是交换内置类型来达到string交换的效果
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

string& operator+=(char ch)
{
	push_back(ch);
	return *this;
}
string& operator+=(const char* str)
{
	append(str);
	return *this;
}
string& operator=(string tmp)
{
	swap(tmp);
	return *this;
}
bool operator<(const string& s) const
{
	return strcmp(_str, s._str) < 0;
}
bool operator<=(const string& s) const
{
	return *this < s || *this == s;
}
bool operator>(const string& s) const
{
	return (*this <= s);
}
bool operator>=(const string& s) const
{
	return !(*this < s);
}
bool operator==(const string& s) const
{
	return strcmp(_str, s._str) == 0;
}
bool operator!=(const string& s) const
{
	return !(*this == s);
}

欢迎捉虫~

相关推荐
闻缺陷则喜何志丹14 分钟前
【贪心 字典序 回文 最长公共前缀】LeetCode3734. 大于目标字符串的最小字典序回文排列|分数未知
c++·算法·力扣·贪心·字典序·回文·最长公共前缀
tung tung tung sahur22 分钟前
领略 Rust 抽象之美:自定义迭代器实现全解析
开发语言·后端·rust
ftpeak28 分钟前
《Rust MP4视频技术开发》第八章:生成MP4
开发语言·rust·音视频·mp4
好学且牛逼的马1 小时前
【SSM框架 | day25 spring IOC 与 DI 注解开发】
java·开发语言
_OP_CHEN1 小时前
C++进阶:(四)set系列容器的全面指南
开发语言·c++·stl·set·multiset·关联式容器·setoj题
不惑_1 小时前
Java 使用 FileOutputStream 写 Excel 文件不落盘?
开发语言·python
十五年专注C++开发1 小时前
Qt-VLC: 一个集成VLC的开源跨平台媒体播放库
开发语言·qt·媒体·libvlc·vlc-qt
郝学胜-神的一滴2 小时前
128天写作之旅:记录与成长的点滴
开发语言·程序人生
superman超哥2 小时前
仓颉语言中流式I/O的设计模式深度剖析
开发语言·后端·设计模式·仓颉
豆浆whisky2 小时前
Go内存管理最佳实践:提升性能的Do‘s与Don‘ts|Go语言进阶(17)
开发语言·后端·golang