嘿嘿,家人们,今天咱们来模拟实现string,好啦,废话不多讲,开干!
1:string.h
1.1:构造函数与拷贝构造函数
1.1.1:写法一
1.1.2:写法二(给缺省值)
1.2:赋值运算符重载与operatror[]获取元素
1.3:容量与迭代器
1.4:reserve与resize
1.5:清空与判断是否为空
1.6:push_back与append
1.7:insert
1.7.1:插入字符
1.7.2:插入字符串
1.8:erase
1.9:operator+=
1.9.1:添加字符
1.9.2:添加字符串
1.91:find
1.91.1:查找字符
1.91.2:查找字符串
1.92:substr与swap
1.93:非成员函数的重载
1.93.1:流插入与流提取的重载
1.93.2:其他非成员函数的重载
2:Test.cpp
2.1:构造函数与拷贝构造
2.1.1:测试写法一
2.1.2:测试写法二
2.2:测试赋值运算符重载与[]获取元素
2.3:测试迭代器与容量
2.4:测试reserve与resize
2.4.1:测试resize
2.4.2:测试reserve
2.5:测试push_back与append
2.6:测试insert
2.6.1:测试插入字符
2.6.2:测试插入字符串
2.7:测试erase
2.8:测试operator+=
2.9:测试find
2.91:测试substr与swap
2.92:测试流插入与流提取
2.92.1:第一版流提取
2.92.2:第二版流提取
2.93:测试其他非成员函数
3:知识补充
3.1:深拷贝与浅拷贝
3.1.1:浅拷贝
3.1.2:深拷贝
4:总代码
4.1:string.h
4.2:Test.cpp
1:string.h
1.1:构造函数与拷贝构造函数
1.1.1:写法一
#include <iostream>
#include <string.h>
#include <assert.h>
using namespace std;
//避免与库中的string冲突,因此使用命名空间
namespace MyString
{
	class string
	{
	public:
		string()
			:_str(new char[1])
			, _size(0)
			,_capacity(0)
		{
			//空字符串只有\0,
			_str[0] = '\0';
		}
		//构造非空字符串
		string(const char * str)
			//开辟空间,多开辟个空间存放\0
			:_str(new char[strlen(str) + 1])
		{
			//开辟空间
			_capacity = _size = strlen(str);
			//拷贝数据
			strcpy(_str, str);
		}
		//拷贝构造函数
		//s2(s1),使用s1拷贝构造s2
		string(string & s)
		{
			//开辟空间
			char* temp = new char[s._capacity + 1];
			_str = temp;
			_capacity = s._capacity;
			_size = s._size;
			//拷贝数据
			strcpy(_str, s._str);
		}
		//析构函数
		~string()
		{
			delete[] _str;
			_size = _capacity = 0;
		}
		
	private:
		//定义成员变量并且给缺省值
		char* _str;
		int   _size;
		int   _capacity;
	};
}
1.1.2:写法二(给缺省值)
#include <iostream>
#include <string.h>
#include <assert.h>
using namespace std;
//避免与库中的string冲突,因此使用命名空间
namespace MyString
{
	class string
	{
	public:
		//string()
		//	:_str(new char[1])
		//	, _size(0)
		//	,_capacity(0)
		//{
		//	//空字符串只有\0,
		//	_str[0] = '\0';
		//}
		构造非空字符串
		//string(const char * str)
		//	//开辟空间,多开辟个空间存放\0
		//	:_str(new char[strlen(str) + 1])
		//{
		//	//开辟空间
		//	_capacity = _size = strlen(str);
		//	//拷贝数据
		//	strcpy(_str, str);
		//}
		//给缺省值,构造空字符串时使用缺省值
		string(const char* str = "")
			//开辟空间,多开辟个空间存放\0
			:_str(new char[strlen(str) + 1])
		{
			//开辟空间
			_capacity = _size = strlen(str);
			//拷贝数据
			strcpy(_str, str);
		}
		/*拷贝构造函数
		s2(s1),使用s1拷贝构造s2*/
		string(string & s)
		{
			//开辟空间
			char* temp = new char[s._capacity + 1];
			_str = temp;
			_capacity = s._capacity;
			_size = s._size;
			//拷贝数据
			strcpy(_str, s._str);
		}
		//析构函数
		~string()
		{
			delete[] _str;
			_size = _capacity = 0;
		}
		
	private:
		//定义成员变量并且给缺省值
		char* _str = nullptr;
		int   _size = 0;
		int   _capacity = 0;
	};
}
1.2:赋值运算符重载与operatror[]获取元素
		//s1 = s2 this---->s1   s2----->s
		//赋值运算符重载
		string & operator =(string & s)
		{
			//开辟新空间
			char * temp = new char[s._capacity + 1];
			//释放旧空间
			delete _str;
			//拷贝数据
			strcpy(temp, s._str);
			//指向新空间
			_str = temp;
			_size = s._size;
			_capacity = s._capacity;
			return *this;
		}
		//T &,返回引用同样可以提高效率,有返回值的目的是为了支持连续赋值.
		char & operator[](size_t position)
		{
			assert(position < _size);
			return _str[position];
		}
		//const成员函数,给const对象调用,与上面构成函数重载
		const char& operator[](size_t position) const
		{
			assert(position < _size);
			return _str[position];
		}
1.3:容量与迭代器
迭代器呢其实是一个类指针,因此我们在模拟实现的时候,直接通过指针来进行模拟即可~
#include <iostream>
#include <string.h>
#include <assert.h>
using namespace std;
//避免与库中的string冲突,因此使用命名空间
namespace MyString
{
	class string
	{
		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;
		}
		//capacity
		size_t size()
		{
			return _size;
		}
	
		size_t capacity()
		{
			return _capacity;
		}
	
		
	private:
		//定义成员变量并且给缺省值
		char* _str = nullptr;
		int   _size = 0;
		int   _capacity = 0;
	};
}
1.4:reserve与resize
我们来回顾下reserve与resize的相关知识
1:reserve
- 比size小不变化
- 比size大但小于capacity也不发生变化
比capacity大才会进行扩容
因此我们只要判断是否比capacity大
2:resize
比size小则进行删除.
- 比size大但小于capacity会改变size,并用\0插入.
比capacity大,会先改变size的大小同时进行扩容.
		//仅需判断是否比capacity大
		void reserve(size_t n)
		{
			if(n > _capacity)
			{
				//开辟新空间
				char* temp = new char[n + 1];
				//拷贝数据
				strcpy(temp, _str);
				//释放旧空间
				delete[] _str;
				//指向新空间
				_str = temp;
				_capacity = n;
				
			}
		}
		void resize(size_t n,char ch = '\0')
		{
			//比size小则会进行删除
			if (n <= _size)
			{
				_str[n] = ch;
			}
			//比size大比capacity小会改变size,并且用\0插入
			else if( n > _size && n <= _capacity)
			{
				_size = n;
			}
			//比capacity大, 会先改变size的大小同时进行扩容.
			else
			{
				//扩容
				reserve(n);
				for(size_t i = _size; i < _capacity ; i++)
				{
					_str[i] = ch;
				}
				_size = n;
			}
		}1.5:清空与判断是否为空
		//只清除有效字符,不改变底层空间
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
		bool empty()const
		{
			return _size == 0;
		}这里博主就不带着uu们测试啦,感兴趣的uu可以自己下去测试下~
1.6:push_back与append
		//Modifiers
		void push_back(char ch)
		{
			//检查容量
			if (_size == _capacity)
				//二倍扩容
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}
		void append(const char * str)
		{
			assert(str);
			//求出添加的字符串的长度
			int length = strlen(str);
			//判断添加后的有效字符数量是否越过容量
			if (_size + length > _capacity)
				reserve(_size + length);
			//_str + _size的位置为\0
			strcpy(_str + _size, str);
            _size += length;
		}
1.7:insert
1.7.1:插入字符
	
		string & insert(size_t position,char ch)
		{
			assert(position <= _size);
			if (_size == _capacity)
				//二倍扩容
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			//从后向前挪动覆盖
			for(int i = _size - 1; i >= position ;i--)
			{
				_str[i + 1] = _str[i];
			}
			_str[position] = ch;
			_size++;
			_str[_size] = '\0';
			return *this;
		}1.7.2:插入字符串
		string & insert(size_t position,const char * str)
		{
			assert(position <= _size);
			int length = strlen(str);
			if (_size + length > _capacity)
				reserve(_size + length);
			//从后向前挪动覆盖
			//_size + length - 1表示挪动的字符串的重点,positon + length表示挪动的字符串的起点
			for(int i = _size + length - 1; i >= position + length; i--)
			{
				_str[i] = _str[i - length];
			}
			//拷贝数据
			strncpy(_str + position, str, length);
			_size += length;
			_str[_size] = '\0';
			return *this;
		}1.8:erase
		void erase(size_t position = 0,size_t len = -1)
		{
			//防止越界
			assert(position < _size);
			//len == -1:如果 len 为 -1,表示删除到字符串末尾。
			//len >= _size - pos,如果 len 超过从 pos 开始的剩余字符长度,同样认为是删除到末尾。
			if(len == -1 || len >= _size - position)
			{
				_str[position] = '\0';
				_size = position;
			}
			else
			{
				//将 pos + len 后的字符串内容复制到 pos 位置,从而覆盖中间 len 长度的字符,实现删除操作
				strcpy(_str + position, _str + position + len);
			}
		}1.9:operator+=
1.9.1:添加字符
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
1.9.2:添加字符串
		string& operator+=(const char * str)
		{
			append(str);
			return *this;
		}1.91:find
1.91.1:查找字符
		//添加const修饰,令const成员与非const成员均可调用
		size_t find(char ch, size_t pos = 0) const
		{
			for(size_t i = pos; i < _size;i++)
			{
				if (_str[i] == ch)
					return i;
			}
			return -1;
		}1.91.2:查找字符串
		const char * c_str()const
		{
			return _str;
		}
		//添加const修饰,令const成员与非const成员均可调用
		size_t find(const char * str,size_t pos = 0	)const
		{
			const char* p = strstr(_str + pos, str);
			if(p != NULL)
			{
				//指针 - 指针得到对应的首字符下标
				return p - _str;
			}
			return -1;
		}1.92:substr与swap
		string substr(size_t pos = 0, size_t len = -1)
		{
			string substr;
			//len == -1:如果 len 为 -1,表示全部获取。
			//len > _size - pos,如果 len 超过从 pos 开始的剩余字符长度,同样认为是全部获取
			if(len > _size - pos || len == -1)
			{
				for(size_t i = 0; i < _size; i++)
				{
					substr += _str[i];
				}
			}
			else
			{
				for(size_t i = pos; i < pos + len;i++)
				{
					substr += _str[i];
				}
			}
			return substr;
		}
		//s1.swap(s2)
		void swap(string & str)
		{
			std::swap(_str, str._str);
			std::swap(_size, str._size);
			std::swap(_capacity, str._capacity);
		}
1.93:非成员函数的重载
1.93.1:流插入与流提取的重载
	ostream& operator<<(ostream& _cout,MyString::string& str)
	{
		for (auto ch : str)
		{
			cout << ch;
		}
		return _cout;
	}
    istream& operator>>(istream& _cin, MyString::string& str)
	{
		第一版:会导致空间的浪费
		//char ch;
		_cin是无法读到\n与' '的
		//ch = _cin.get();
		清空字符
		//str.clear();
		//while (ch != '\n' && ch != ' ')
		//{
		//	str += ch;
		//	ch = _cin.get();
		//}
		//return _cin;
		//第二版
		char ch;
		ch = _cin.get();
		//底层给个buff
		char buff[128];
		size_t i = 0;
		//将原本的字符清空
		str.clear();
		//cin无法读取' '与'\n'
		while (ch != '\n' && ch != ' ')
		{
			buff[i++] = ch;
			//最后一个字符设置为\0
			if(i == 127)
			{
				buff[i] = '\0';
				str += buff;
			}
			//持续读取字符
			ch = _cin.get();
		}
		if(i > 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return _cin;
	} 
}
按照常规方式,流提取按照上面的第一版方式进行重载即可,但是,底层其实是给了buff,目的是: 防止空间的浪费,因为按照常规方式重载的话,那么在 扩容的时候一般是1.5倍或者2倍扩容,而通过给一个buff,能够最大程度地防止空间的浪费.
1.93.2:其他非成员函数的重载
	//会先调用此swap,有现成的,吃现成的,不使用模版里面的swap
	void swap(string& x, string& y)
	{
		x.swap(y);
	}
	//自定义类型传值传参会调用拷贝构造,因此需要传引用
	bool operator==(const MyString::string& str1, const  MyString::string& str2)
	{
		int result = strcmp(str1.c_str(), str2.c_str());
		return result == 0;
	}
	bool operator<(const  MyString::string& str1, const MyString::string& str2)
	{
		int result = strcmp(str1.c_str(), str2.c_str());
		return result < 0;
	}
	bool operator>(const  MyString::string& str1, const  MyString::string& str2)
	{
		int result = strcmp(str1.c_str(), str2.c_str());
		return result > 0;
	}
	bool operator<=(const  MyString::string& str1, const  MyString::string& str2)
	{
		return (str1 < str2) || (str1 == str2);
	}
	bool operator>=(const  MyString::string& str1, const  MyString::string& str2)
	{
		return !(str1 < str2);
	}
	bool operator!=(const  MyString::string& str1, const  MyString::string& str2)
	{
		return !(str1 == str2);
	}2:Test.cpp
2.1:构造函数与拷贝构造
2.1.1:测试写法一
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestConstructionAndCopyConstruction()
{
	MyString::string s1;
	MyString::string s2("hello world");
	MyString::string s3(s2);
}
int main()
{
	TestConstructionAndCopyConstruction();
	return 0;
}
2.1.2:测试写法二
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestConstructionAndCopyConstruction()
{
	MyString::string s1;
	MyString::string s2("hello world");
	MyString::string s3(s2);
}
int main()
{
	TestConstructionAndCopyConstruction();
	return 0;
}
2.2:测试赋值运算符重载与[]获取元素
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestAssignmentOperatorOverloadingAndElementAccess()
{
	MyString::string s1;
	MyString::string s2("hello world");
	const MyString::string s3("hello Linux");
	s1 = s2;
	cout <<"s1[0]:>" << s1[0] << endl;
	cout <<"s3[6]:>" << s3[6] << endl;
}
int main()
{
	TestAssignmentOperatorOverloadingAndElementAccess();
	return 0;
}
2.3:测试迭代器与容量
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestIteratorAndCapacity()
{
	MyString::string s1;
	MyString::string s2("hello world");
	s1 = s2;
	for(auto & element : s2)
	{
		cout << element << endl;
	}
	cout <<"s2.size()" << s2.size() << endl;
	cout <<"s2.capacity()" << s2.capacity() << endl;
}
int main()
{
	TestIteratorAndCapacity();
	return 0;
}
2.4:测试reserve与resize
2.4.1:测试resize

#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestResize()
{
	MyString::string str("hello world");
	//比size小则进行删除
	str.resize(10);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << endl;
	//比size大但小于capacity会用改变size,并用\0插入
	str.resize(13);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << endl;
	//比capacity大,会先改变size的大小同时进行扩容
	str.resize(20);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
}
int main()
{
	TestResize();
	return 0;
}2.4.2:测试reserve
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestRserve()
{
	MyString::string str("hello world");
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << "reserver后" << endl;
	cout << endl;
	//比size小不变化
	str.reserve(10);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << endl;
	//比size大但小于capacity也不发生变化
	str.reserve(13);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << endl;
	//比capacity大才会进行扩容
	str.reserve(20);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
}
int main()
{
	TestRserve();
	return 0;
}
2.5:测试push_back与append
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestPushBackAndAppend()
{
	MyString::string str;
	str.append("hello world");
	str.push_back('x');
}
int main()
{
	TestPushBackAndAppend();
	return 0;
}2.6:测试insert
2.6.1:测试插入字符
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestInsert() 
{
	MyString::string str("hello world");
	//在下标为5的位置插入字符h
	str.insert(5, 'h');
}
int main()
{
	TestInsert();
	return 0;
}2.6.2:测试插入字符串
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestInsert() 
{
	MyString::string str("hello world");
	//在下标为5的位置插入字符h
	str.insert(5, 'h');
	str.insert(2, "Linux");
}
int main()
{
	TestInsert();
	return 0;
}2.7:测试erase
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestErase()
{
	MyString::string str("hello world");
	str.erase(2, 4);
}
int main()
{
	TestErase();
	return 0;
} 
2.8:测试operator+=
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void Test()
{
	MyString::string str("hello");
	str += ' ';
	str += "Linux";
}
int main()
{
	Test();
	return 0;
}
2.9:测试find
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestFind() 
{
	MyString::string str("hello Linux");
	cout << str.find('l', 2) << endl;
	cout << str.find("Linux", 2) << endl;
}
int main()
{
	TestFind();
	return 0;
}2.91:测试substr与swap
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestSwapAndSubstr()
{
	MyString::string s1("hello Linux");
	MyString::string s2("hello bit");
	MyString::string temp = s1.substr(6, 5);
	cout << "交换前" << endl;
	cout << "s1:>" << s1 << endl;
	cout << "s2:>" << s2 << endl;
	cout <<"temp:>" << temp << endl;
	s1.swap(s2);
	cout << "交换后" << endl;
	cout <<"s1:>" << s1 << endl;
	cout <<"s2:>" << s2 << endl;
}
int main()
{
	TestSwapAndSubstr();
	return 0;
}2.92:测试流插入与流提取
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestStreamInsertionAndStreamExtraction()
{
	MyString::string s1;
	cin >> s1;
	cout << s1 << endl;
	cout << "s1.size:>" << s1.size() << endl;
	cout << "s1.capacity:>" << s1.capacity() << endl;
}
int main()
{
	TestStreamInsertionAndStreamExtraction();
	return 0;
}2.92.1:第一版流提取

2.92.2:第二版流提取

2.93:测试其他非成员函数
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestOtherFunction()
{
	MyString::string s1("hello world");
	MyString::string s2("hello bit");
	swap(s1, s2);
	s1.swap(s2);
	cout << s1.c_str() << endl;
	cout << s2.c_str() << endl;
	cout << (s1 == s2) << endl;
	cout << (s1 >= s2) << endl;
	cout << (s1 > s2) << endl;
	cout << (s1 < s2) << endl;
	cout << (s1 <= s2) << endl;
	cout << (s1 != s2) << endl;
}
int main()
{
	TestOtherFunction();
	return 0;
}
3:知识补充
3.1:深拷贝与浅拷贝
在讲深浅拷贝之前,我们来看一个现象

我们可以清晰地看到,s2与s3的地址一样,这是为什么呢,因为博主将显示定义的拷贝构造函数给屏蔽了,因此在拷贝构造s3时会调用编译器默认的拷贝构造函数,那么这就会导致一个问题:
s2与s3共用同一块内存空间,在释放时同一块内存空间被释放多次而会引起程序崩溃,这种方式被称作浅拷贝.

3.1.1:浅拷贝
浅拷贝:又被称作位拷贝,编译器直接是将另外一个对象的值拷贝复制过来.如果对象中管理资源,那么最后就会导致多个对象共享一份资源,当一个对象销毁时就会将资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还是有效的,那么因此当继续对资源进行操作时,就会发生访问违规~
举一个简单例子
就像一个家庭中有两个孩子,但父母只买了一份玩具,两个孩子愿意一块玩,则万事大吉,万一不想分享就你争我抢,玩具损坏.
 
 
 
 
那么该如何解决浅拷贝的问题呢,用深拷贝就可以即每个对象都有一份独立的资源,不要和其他对象共享。父母给每个孩子都买一份玩具,各自玩各自的就不会有存在任何矛盾.
 3.1.2:深拷贝
 3.1.2:深拷贝
 
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出,一般情况都是按照深拷贝方式提供.
4:总代码
4.1:string.h
#include <iostream>
#include <string.h>
#include <assert.h>
using namespace std;
//避免与库中的string冲突,因此使用命名空间
namespace MyString
{
	class string
	{
		typedef char* iterator;
		typedef const char* const_iterator;
	public:
		//string()
		//	:_str(new char[1])
		//	, _size(0)
		//	,_capacity(0)
		//{
		//	//空字符串只有\0,
		//	_str[0] = '\0';
		//}
		构造非空字符串
		//string(const char * str)
		//	//开辟空间,多开辟个空间存放\0
		//	:_str(new char[strlen(str) + 1])
		//{
		//	//开辟空间
		//	_capacity = _size = strlen(str);
		//	//拷贝数据
		//	strcpy(_str, str);
		//}
		//给缺省值,构造空字符串时使用缺省值
		string(const char* str = "")
			//开辟空间,多开辟个空间存放\0
			:_str(new char[strlen(str) + 1])
		{
			//开辟空间
			_capacity = _size = strlen(str);
			//拷贝数据
			strcpy(_str, str);
		}
		/*拷贝构造函数
		s2(s1),使用s1拷贝构造s2*/
		string(string& s)
		{
			//开辟空间
			char* temp = new char[s._capacity + 1];
			_str = temp;
			_capacity = s._capacity;
			_size = s._size;
			//拷贝数据
			strcpy(_str, s._str);
		}
		//s1 = s2 this---->s1   s2----->s
		//赋值运算符重载
		string& operator =(string& s)
		{
			//开辟新空间
			char* temp = new char[s._capacity + 1];
			//释放旧空间
			delete _str;
			//拷贝数据
			strcpy(temp, s._str);
			//指向新空间
			_str = temp;
			_size = s._size;
			_capacity = s._capacity;
			return *this;
		}
		//T &,返回引用同样可以提高效率,有返回值的目的是为了支持连续赋值.
		char& operator[](size_t position)
		{
			assert(position < _size);
			return _str[position];
		}
		//const成员函数,给const对象调用,与上面构成函数重载
		const char& operator[](size_t position) const
		{
			assert(position < _size);
			return _str[position];
		}
		///
		//iteraor
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		//设置成员函数
		const_iterator begin() const
		{
			return _str;
		}
		const_iterator end() const
		{
			return _str + _size;
		}
		//capacity
		size_t size()
		{
			return _size;
		}
		size_t capacity()
		{
			return _capacity;
		}
		//仅需判断是否比capacity大
		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				//开辟新空间
				char* temp = new char[n + 1];
				//拷贝数据
				strcpy(temp, _str);
				//释放旧空间
				delete[] _str;
				//指向新空间
				_str = temp;
				_capacity = n;
			}
		}
		void resize(size_t n, char ch = '\0')
		{
			//比size小则会进行删除
			if (n <= _size)
			{
				_str[n] = ch;
			}
			//比size大比capacity小会改变size,并且用\0插入
			else if (n > _size && n <= _capacity)
			{
				_size = n;
			}
			//比capacity大, 会先改变size的大小同时进行扩容.
			else
			{
				//扩容
				reserve(n);
				for (size_t i = _size; i < _capacity; i++)
				{
					_str[i] = ch;
				}
				_size = n;
			}
		}
		//Modifiers
		void push_back(char ch)
		{
			//检查容量
			if (_size == _capacity)
				//二倍扩容
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}
		void append(const char* str)
		{
			assert(str);
			//求出添加的字符串的长度
			int length = strlen(str);
			//判断添加后的有效字符数量是否越过容量
			if (_size + length > _capacity)
				reserve(_size + length);
			//_str + _size的位置为\0
			strcpy(_str + _size, str);
			_size += length;
		}
		string& insert(size_t position, char ch)
		{
			assert(position <= _size);
			if (_size == _capacity)
				//二倍扩容
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			//从后向前挪动覆盖
			for (int i = _size - 1; i >= position; i--)
			{
				_str[i + 1] = _str[i];
			}
			_str[position] = ch;
			_size++;
			_str[_size] = '\0';
			return *this;
		}
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
		bool empty()const
		{
			return _size == 0;
		}
		string& insert(size_t position, const char* str)
		{
			assert(position <= _size);
			int length = strlen(str);
			if (_size + length > _capacity)
				reserve(_size + length);
			//从后向前挪动覆盖
			//_size + length - 1表示挪动的字符串的重点,positon + length表示挪动的字符串的起点
			for (int i = _size + length - 1; i >= position + length; i--)
			{
				_str[i] = _str[i - length];
			}
			//拷贝数据
			strncpy(_str + position, str, length);
			_size += length;
			_str[_size] = '\0';
			return *this;
		}
		void erase(size_t position = 0, size_t len = -1)
		{
			//防止越界
			assert(position < _size);
			//len == -1:如果 len 为 -1,表示删除到字符串末尾。
			//len >= _size - pos,如果 len 超过从 pos 开始的剩余字符长度,同样认为是删除到末尾。
			if (len == -1 || len >= _size - position)
			{
				_str[position] = '\0';
				_size = position;
			}
			else
			{
				//将 pos + len 后的字符串内容复制到 pos 位置,从而覆盖中间 len 长度的字符,实现删除操作
				strcpy(_str + position, _str + position + 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;
		}
		//添加const修饰,令const成员与非const成员均可调用
		size_t find(char ch, size_t pos = 0) const
		{
			for(size_t i = pos; i < _size;i++)
			{
				if (_str[i] == ch)
					return i;
			}
			return -1;
		}
		//添加const修饰,令const成员与非const成员均可调用
		size_t find(const char * str,size_t pos = 0	)const
		{
			const char* p = strstr(_str + pos, str);
			if(p != NULL)
			{
				//指针 - 指针得到对应的首字符下标
				return p - _str;
			}
			return -1;
		}
		string substr(size_t pos = 0, size_t len = -1)
		{
			string substr;
			//len == -1:如果 len 为 -1,表示全部获取。
			//len > _size - pos,如果 len 超过从 pos 开始的剩余字符长度,同样认为是全部获取
			if(len > _size - pos || len == -1)
			{
				for(size_t i = 0; i < _size; i++)
				{
					substr += _str[i];
				}
			}
			else
			{
				for(size_t i = pos; i < pos + len;i++)
				{
					substr += _str[i];
				}
			}
			return substr;
		}
		//s1.swap(s2)
		void swap(string & str)
		{
			std::swap(_str, str._str);
			std::swap(_size, str._size);
			std::swap(_capacity, str._capacity);
		}
		//析构函数
		~string()
		{
			delete[] _str;
			_size = _capacity = 0;
		}
		
	private:
		//定义成员变量并且给缺省值
		char* _str = nullptr;
		int   _size = 0;
		int   _capacity = 0;
	};
	//Non-member_function_overloads
	ostream& operator<<(ostream& _cout,MyString::string& str)
	{
		for (auto ch : str)
		{
			cout << ch;
		}
		return _cout;
	}
	istream& operator>>(istream& _cin, MyString::string& str)
	{
		第一版:会导致空间的浪费
		//char ch;
		_cin是无法读到\n与' '的
		//ch = _cin.get();
		清空字符
		//str.clear();
		//while (ch != '\n' && ch != ' ')
		//{
		//	str += ch;
		//	ch = _cin.get();
		//}
		//return _cin;
		//第二版
		char ch;
		ch = _cin.get();
		//底层给个buff
		char buff[128];
		size_t i = 0;
		//将原本的字符情况
		str.clear();
		//cin无法读取' '与'\n'
		while (ch != '\n' && ch != ' ')
		{
			buff[i++] = ch;
			//最后一个字符设置为\0
			if(i == 127)
			{
				buff[i] = '\0';
				str += buff;
			}
			//持续读取字符
			ch = _cin.get();
		}
		if(i > 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return _cin;
	}
	//会先调用此swap,有现成的,吃现成的,不使用模版里面的swap
	void swap(string& x, string& y)
	{
		x.swap(y);
	}
	//自定义类型传值传参会调用拷贝构造,因此需要传引用
	bool operator==(const MyString::string& str1, const  MyString::string& str2)
	{
		int result = strcmp(str1.c_str(), str2.c_str());
		return result == 0;
	}
	bool operator<(const  MyString::string& str1, const MyString::string& str2)
	{
		int result = strcmp(str1.c_str(), str2.c_str());
		return result < 0;
	}
	bool operator>(const  MyString::string& str1, const  MyString::string& str2)
	{
		int result = strcmp(str1.c_str(), str2.c_str());
		return result > 0;
	}
	bool operator<=(const  MyString::string& str1, const  MyString::string& str2)
	{
		return (str1 < str2) || (str1 == str2);
	}
	bool operator>=(const  MyString::string& str1, const  MyString::string& str2)
	{
		return !(str1 < str2);
	}
	bool operator!=(const  MyString::string& str1, const  MyString::string& str2)
	{
		return !(str1 == str2);
	}
}
4.2:Test.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "String.h"
void TestConstructionAndCopyConstruction()
{
	MyString::string s1;
	MyString::string s2("hello world");
	MyString::string s3(s2);
}
void TestAssignmentOperatorOverloadingAndElementAccess()
{
	MyString::string s1;
	MyString::string s2("hello world");
	const MyString::string s3("hello Linux");
	s1 = s2;
	cout <<"s1[0]:>" << s1[0] << endl;
	cout <<"s3[6]:>" << s3[6] << endl;
}
void TestIteratorAndCapacity()
{
	MyString::string s1;
	MyString::string s2("hello world");
	s1 = s2;
	for(auto & element : s2)
	{
		cout << element;
	}
	cout << endl;
	cout <<"s2.size():>" << s2.size() << endl;
	cout <<"s2.capacity():>" << s2.capacity() << endl;
}
void TestResize()
{
	MyString::string str("hello world");
	//比size小则进行删除
	str.resize(10);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << endl;
	//比size大但小于capacity会用改变size,并用\0插入
	str.resize(13);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << endl;
	//比capacity大,会先改变size的大小同时进行扩容
	str.resize(20);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
}
void TestRserve()
{
	MyString::string str("hello world");
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << "reserver后" << endl;
	cout << endl;
	//比size小不变化
	str.reserve(10);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << endl;
	//比size大但小于capacity也不发生变化
	str.reserve(13);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << endl;
	//比capacity大才会进行扩容
	str.reserve(20);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
}
void TestPushBackAndAppend()
{
	MyString::string str;
	str.append("hello world");
	str.push_back('x');
}
void TestInsert() 
{
	MyString::string str("hello world");
	//在下标为5的位置插入字符h
	str.insert(5, 'h');
	str.insert(2, "Linux");
}
void TestErase()
{
	MyString::string str("hello world");
	str.erase(2, 4);
}
void Test()
{
	MyString::string str("hello");
	str += ' ';
	str += "Linux";
}
void TestFind() 
{
	MyString::string str("hello Linux");
	cout << str.find('l', 2) << endl;
	cout << str.find("Linux", 2) << endl;
}
void TestSwapAndSubstr()
{
	MyString::string s1("hello Linux");
	MyString::string s2("hello bit");
	MyString::string temp = s1.substr(6, 5);
	cout << "交换前" << endl;
	cout << "s1:>" << s1 << endl;
	cout << "s2:>" << s2 << endl;
	cout <<"temp:>" << temp << endl;
	s1.swap(s2);
	cout << "交换后" << endl;
	cout <<"s1:>" << s1 << endl;
	cout <<"s2:>" << s2 << endl;
}
void TestStreamInsertionAndStreamExtraction()
{
	MyString::string s1;
	cin >> s1;
	cout << s1 << endl;
	cout << "s1.size:>" << s1.size() << endl;
	cout << "s1.capacity:>" << s1.capacity() << endl;
}
void TestOtherFunction()
{
	MyString::string s1("hello world");
	MyString::string s2("hello bit");
	swap(s1, s2);
	s1.swap(s2);
	cout << s1.c_str() << endl;
	cout << s2.c_str() << endl;
	cout << (s1 == s2) << endl;
	cout << (s1 >= s2) << endl;
	cout << (s1 > s2) << endl;
	cout << (s1 < s2) << endl;
	cout << (s1 <= s2) << endl;
	cout << (s1 != s2) << endl;
}
int main()
{
	TestConstructionAndCopyConstruction();
	TestAssignmentOperatorOverloadingAndElementAccess();
	TestIteratorAndCapacity();
	TestResize();
	TestRserve();
	TestPushBackAndAppend();
	TestInsert();
	TestErase();
	Test();
	TestFind();
	TestSwapAndSubstr();
	TestStreamInsertionAndStreamExtraction();
	TestOtherFunction();
	return 0;
}好啦,uu们,string的模拟实现这部分滴详细内容博主就讲到这里啦,如果uu们觉得博主讲的不错的话,请动动你们滴小手给博主点点赞,你们滴鼓励将成为博主源源不断滴动力,同时也欢迎大家来指正博主滴错误~




























