C++模拟实现string类

一、构造相关

构造函数

用初始化列表声明时注意声明顺序
char*类型构造
用strcpy函数实现,strcpy拷贝时会自动拷贝’\0’

string(const char* str = "")
//初始化的顺序只和成员变量声明的顺序有关
	:_size(strlen(str))
	, _capacity(_size)
	, _str(new char[_size + 1])
{
	strcpy(_str, str);
}

n个字符构造
调用memset函数实现,结尾加’\0’

string(size_t n, char ch)
{
	_size = n;
	_capacity = _size;
	_str = new char[_size + 1];
	memset(_str, ch, n);
	_str[n] = '\0';//结尾
}

拷贝构造函数

现代版写法
复用构造函数定义临时变量,使用swap函数对两个对象的_str进行交换,注意这里的swap是函数模板,可以交换任意类型,非string类成员函数

string(const string& s)
	:_str(nullptr)
{
	string temp(s._str);
	//std::swap(temp, *this);
	std::swap(_str, temp._str);
}

传统版写法

申请空间,调用strcpy进行拷贝

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

析构函数

删除空间,置空指针

~string()
{
	delete[]_str;
	_str = nullptr;
}

赋值运算符重载

现代版写法1
采用传值传参,不用定义临时变量

string& operator=(string s)
{
	std::swap(_str, s._str);
	return *this;
}

现代版写法2
传引用传参,需判断是否给自己赋值,且要定义临时变量,复用拷贝构造函数

string& operator=(const string& s)
{
	if (this != &s)
	{
		string temp(s);//调用拷贝构造
		swap(_str, temp._str);//temp被销毁后自动释放旧空间
	}
}

传统版写法
⭐直接让_str指向申请的新空间,旧的空间无法释放;而如果先删除旧空间,new可能会申请失败。所以必须定义临时变量。

string& operator=(const string& s)
{
	if (this != &s)
	{
		char* temp = new char[strlen(s._str) + 1];
		strcpy(temp, s._str);
		delete _str;
		_str = temp;
	}
	return *this;
}

二、迭代器

定义

将指针当作迭代器使用

typedef char* iterator;
typedef char* reverse_iterator;

正向迭代器

iterator begin()
{
	return _str;
}
iterator end()
{
	return _str + _size;
}

三、容量相关

size、lenth

size和lenth含义相同,但lenth为string类独有

size_t size()
{
	return _size;
}
size_t lenth()
{
	return _size;
}

capacity

size_t capacity()
{
	return _capacity;
}

empty

判断当前对象内容是否为空

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

clear

清空内容,但不影响容量

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

resize

改变有效元素个数,如果空间不够要进行扩容,复用append函数,给新增的空间填充内容;如果是减小有效元素个数,将’\0’前移即可。注意改变_size的值

void resize(size_t newsize, char ch = '\0')
{
	if (newsize > _size){
		if (newsize > _capacity){
			reserve(newsize);
		}
		//扩容的空间用ch填充
		append(newsize - _size, ch);
	}
	else{
		_str[newsize] = '\0';
	}
	_size = newsize;
}

reserve

申请新空间,拷贝元素,删除旧空间。注意改变_capacity的值

void reserve(size_t newcapacity)
{
	if (newcapacity > _capacity)
	{
		char* temp = new char[newcapacity + 1];//+1保存'\0'
		strcpy(temp, _str);
		delete[] _str;
		_str = temp;
		_capacity = newcapacity;
	}
}

四、元素访问

"[]"符合重载

重载成两种形式,普通成员函数和const成员函数;const成员函数可以访问const成员变量。

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

五、元素修改

+=

拼接string类对象
复用append

string& operator+=(string& s)
{
	append(s);
	return *this;
}

拼接单个字符

string& operator+=(char c)
{
	append(1, c);
	return *this;
}

拼接char*类型字符串

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

⭐append

追加多个字符
判断追加后的空间若大于_capacity,则需要进行扩容,调用memset函数将空间初始化,注意给空间结尾位置加’\0’

string& append(size_t n, char c)
{
	if (_size + n > _capacity){
		reserve(_size + n);
	}
	//_str+_size 要追加的起始位置
	//memset(_str, c, n);
	memset(_str + _size, c, n);
	_size += n;
	_str[_size + n] = '\0';
	return *this;
}

追加char*类型字符串
调用strcat函数进行字符串拼接

string& append(const char* str)
{
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		reserve(len + _size);
	}
	strcat(_str, str);
	_size += len;
	return *this;
}

追加string类对象
复用c_string函数和追加char*类型字符串的append

string& append(string& s)
{
	append(s.c_string());
	return *this;
}

push_back

复用append,追加一个字符

void push_back(char c)
{
	append(1, c);
}

insert

任意位置的插入,这里插入的是pos位置之前,将pos及其之后的所有元素向后移一个单位,将要插入的字符c放到pos位置,注意给末尾田间’\0’

string& insert(int pos, char c)
{
	if (_size + 1 > _capacity){
		resize(_size + 1);
	}
	//插入在pos之前的位置
	for (int i = _size; i > pos; i--){
		_str[i] = _str[i - 1];
	}
	_str[pos] = c;
	_str[_size + 1] = '\0';
	return *this;
}

erase

npos是形参的默认值,表示size_t类型的最大值,如果len没有给出,则默认从当前位置erase到结尾;循环将pos+len到结尾的元素向前移动len个单位;复用resize函数改变_size大小,并给结尾添加’\0’,返回值为移除后的对象。

string& erase(size_t pos = 0, size_t len = npos)
{
	if (len == npos){
		len = _size - 1;
	}
	for (int i = pos; i + len < _size; i++)//循环条件
	{
		_str[i] = _str[i + len];
	}
	resize(_size - len);
	return *this;
}

swap

使用swap函数模板交换各个成员变量的值

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

六、string类操作

c_string

返回char*类型字符串

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

find

查找某一个字符,返回其第一次出现的位置,未找到则返回npos

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

rfind

反向查找字符,返回其第一次出现的位置

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

substr

截取字串,注意截取字串并不是改变原来的字符串。调用strncopy函数从源字符串pos位置拷贝n个字符。

string substr(size_t pos = 0, size_t len = npos)const
{
	if (len == npos){
		len = _size - pos;
	}
	char* temp = new char[len + 1];
	strncpy(temp, _str + pos, len);
	temp[len] = '\0';
	string s(temp);
	delete[] temp;
	return s;
}

七、比较大小

compare

调用strcmp函数

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

‘>’

bool operator>(const string& s)const
{
	if (strcmp(_str, s._str) == 1)
	{
		return true;
	}
	return false;
}

‘==’

bool operator==(const string& s)const
{
	if (strcmp(_str, s._str) == 0)
	{
		return true;
	}
	return false;
}

‘>=’

复用’>‘和’='即可

bool operator>=(const string& s)const
{
	//复用
	if (*this == s || *this > s)
	{
		return true;
	}
	return false;
}

‘<’

复用’>=‘

bool operator<(const string& s)const
{
	//复用>
	if (*this >= s)
	{
		return false;
	}
	return false;
}

‘<=’

复用’>’

bool operator<=(const string& s)const
{
	if (*this > s)
	{
		return false;
	}
	return true;
}

八、成员变量

static静态成员变量,在类中声明,类外定义

private:
	size_t _size;
	size_t _capacity;
	char* _str;
	static size_t npos;//类中声明为静态成员变量,所有对象可以共享

定义npos

size_t string::npos = -1;//类外定义

九、非类成员函数

因为类成员函数的第一个形参都是this无法修改,而’<<‘和’>>'的重载都要求第一个参数是ostream或istream类的对象,否则重载以后类对象就成为了左操作数,不符合常规:
在这里插入图片描述

流插入运算符’<<'重载

类外定义,类内声明为友元类,可以访问私有成员,返回值和第一个形参类型都是ostream类对象的引用
定义:

ostream& operator<<(ostream& _cout, const string& s)
{
	_cout << s._str;
	return _cout;
}

声明:

friend ostream& operator<<(ostream& _cout, const string& s);

流提取运算符’>>'重载

返回值和参数类型为istream类对象的引用
定义:

istream& operator>>(istream& _cin, string& s)
{
	_cin >> s._str;
	return _cin;
}

声明:

friend istream& operator>>(istream& _cin, string& s);

十、附:完整string类,含测试用例

#define	_CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
#include<string.h>
#include<Windows.h>
using namespace std;


namespace ZH
{
	class string
	{
	public:
		//迭代器
		typedef char* iterator;
		typedef char* reverse_iterator;

		// 构造相关
		//构造函数
		//
		string(const char *str= "")
			//初始化的顺序只和成员变量声明的顺序有关
			:_size (strlen(str))
			,_capacity (_size)
			, _str(new char[_size + 1])
		{
			strcpy(_str, str);
		}
		string(size_t n, char ch)
			/*:_size(n)
			,_capacity(_size)
			,_str(new char[_size+1])*/
		{
			_size=n;
			_capacity = _size;
			_str = new char[_size + 1];
			memset(_str, ch, n);
			_str[n] = '\0';
		}
		//拷贝构造
		string(const string& s)
			:_str(nullptr)
		{
			string temp(s._str);
			//std::swap(temp, *this);
			std::swap(_str, temp._str);
		}
		/*string(const string& s)
		{
			_str = new char[strlen(s._str) + 1];
			strcpy(_str, s._str);
		}*/
		//析构
		~string()
		{
			delete[]_str;
			_str = nullptr;
		}
		//赋值运算符重载
		//传统
		/*string& operator=(const string& s)
		{
			if (this != &s)
			{
				char* temp = new char[strlen(s._str) + 1];
				strcpy(temp, s._str);
				delete _str;
				_str = temp;
			}
			return *this;
		}*/

		/*string& operator=(const string& s)
		{
			if (this != &s)
			{
				string temp(s);//调用拷贝构造
				swap(_str, temp._str);//temp被销毁后自动释放旧空间
			}
		}*/

		string& operator=(string s)
		{
			std::swap(_str, s._str);
			return *this;
		}
		
		//iterator
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		//
		//capacity
		size_t size()
		{
			return _size;
		}
		size_t capacity()
		{
			return _capacity;
		}
		size_t lenth()
		{
			return _size;
		}
		bool empty()
		{
			return _size == 0;
		}
		void clear()
		{
			_str[_size] = '\0';
			_size = 0;	
		}
		void resize(size_t newsize,char ch='\0')
		{
			if (newsize > _size)
			{
				if (newsize > _capacity)
				{
					reserve(newsize);
				}
				//扩容的空间用ch填充
				append(newsize - _size, ch);
			}
			else
			{
				_str[newsize] = '\0';
			}
			_size = newsize;
		}
		void reserve(size_t newcapacity)
		{
			if (newcapacity > _capacity)
			{
				char* temp = new char[newcapacity+1];//+1保存'\0'
				strcpy(temp, _str);
				delete[] _str;
				_str = temp;
				_capacity = newcapacity;
			}
		}
		/
		// access
		char operator[](int n)
		{
			assert(n < _size);
			return _str[n];
		}
		const char operator[](int n)const
		{
			assert(n < _size);
			return _str[n];
		}
		//
		//modifiers
		string& operator+=(string& s)
		{
			append(s);
			return *this;
		}
		string& operator+=(char c)
		{
			append(1,c);
			return *this;
		}
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}

		string& append(size_t n,char c)
		{
			if (_size + n > _capacity)
			{
				reserve(_size + n);
			}
			//_str+_size 要追加的起始位置
			//memset(_str, c, n);
			memset(_str + _size, c, n);
			_size += n;
			_str[_size+n] = '\0';
			return *this;
		}
		string& append(const char*str)
		{
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(len + _size);
			}
			strcat(_str, str);
			_size += len;
			return *this;	
		}
		string& append(string& s)
		{
			append(s.c_string());
			return *this;
		}

		void push_back(char c)
		{
			append(1, c);
		}

		string& insert(int pos, char c)
		{
			if (_size + 1 > _capacity)
			{
				resize(_size + 1);
			}
			//插入在pos之前的位置
			for (int i = _size; i > pos; i--)
			{
				_str[i] = _str[i - 1];
			}
			_str[pos] = c;
			_str[_size + 1] = '\0';
			return *this;
		}
		string& erase(size_t pos = 0, size_t len = npos)
		{
			if (len == npos) {
				len = _size - pos;
			}
			for (int i = pos; i + len < _size; i++)//循环条件
			{
				_str[i] = _str[i + len];
			}
			resize(_size - len);
			return *this;
		}
		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

		//
		//string operations
		const char* c_string()const
		{
			return _str;
		}
		size_t find(char c, size_t pos=0)
		{
			for (int i = pos; i < _size; i++)
			{
				if (_str[i] == c)
				{
					return i;
				}
			}
			return npos;
		}
		size_t rfind(char ch,size_t pos)
		{
			for (int i = _size - 1; i >= 0; i--)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}
		string substr(size_t pos = 0, size_t len = npos)const
		{
			if (len == npos)
			{
				len = _size - pos;
			}
			char* temp = new char[len + 1];
			strncpy(temp, _str + pos, len);
			temp[len] = '\0';

			string s(temp);
			delete[] temp;
			return s;
		}
		//
		//compare
		int compare(const string& s)const
		{
			return(strcmp(_str, s._str));
		}

		bool operator>(const string& s)const
		{
			if (strcmp(_str, s._str) == 1) 
			{
				return true;
			}
			return false;
		}
		bool operator==(const string& s)const
		{
			if (strcmp(_str, s._str) == 0)
			{
				return true;
			}
			return false;
		}
		/*bool operator>=(string& s)
		{
			if (strcmp(_str, s._str) == 1 || strcmp(_str, s._str) == 0)
			{
				return true;
			}
			return false;
		}*/
		bool operator>=(const string& s)const 
		{
			//复用
			if (*this==s|| *this>s)
			{
				return true;
			}
			return false;
		}
		bool operator<(const string& s)const
		{
			//复用>
			if (*this >= s)
			{
				return false;
			}
			return false;
		}
		bool operator<=(const string& s)const
		{
			if (*this > s)
			{
				return false;
			}
			return true;
		}
		//
	//成员变量
		friend ostream& operator<<(ostream& _cout, const string& s);
		friend istream& operator>>(istream& _cin, string& s);

	private:
		size_t _size;
		size_t _capacity;
		char* _str;
		static size_t npos ;//类中声明为静态成员变量,所有对象可以共享
	};



	size_t string::npos = -1;//类外定义

	//流插入运算符重载,类外定义,类内声明为友元类,可以访问私有成员
	ostream& operator<<(ostream& _cout, const string& s)
	{
		_cout << s._str;
		return _cout;
	}
	//流提取运算符重载,类型为istream
	istream& operator>>(istream& _cin, string& s)
	{
		_cin >> s._str;
		return _cin;
	}
}


void Test1()
{
	ZH::string s1("hello world");
	s1.insert(7, 'W');//
}

void Test2()
{
	ZH::string s1("1234");
	s1.resize(10,'c');
	s1.reserve(100);
}

void Test3()
{
	ZH::string s1("0123456789");
	s1.erase(2, 3);
	cout << s1.capacity() << endl;
}
void Test4()
{
	ZH::string s1("hello");
	ZH::string s2("world");
	s1.swap(s2);
}
void Test5()
{
	ZH::string s1("hello");
	s1 += 'w';
	const ZH::string s2("hello");
	cout << s2[1];
}
void Test6()
{
	ZH::string s1("hello world");
	ZH::string s2(s1);
	cout << s2 << endl;
	string s3;
	cin >> s3;
	cout << s3 << endl;
}
void Test7()
{
	ZH::string s1("world");
	ZH::string s2("linux");
	ZH::string s3("hello");
	bool a=s1.compare(s2);
	bool b = s3.compare(s1);
	bool c = s3.compare(s3);
	cout << a << b << c << endl;
}

void Test8()
{
	ZH::string s1("world");
	ZH::string s2("linux");
	ZH::string s3("hello");
	ZH::string s4("hello");
	bool a = s1 > s2;
	bool b = s3 < s4;;
	bool c = s4 == s4;
}

void Test9()
{
	ZH::string s("data");
	s.reserve(10);
	s.insert(1, 'd');
	cout << s;
}

int main()
{
	Test3();
	
	system("pause");
	return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值