0
点赞
收藏
分享

微信扫一扫

9.string模拟实现

_karen 2022-04-13 阅读 33
c++

目录

1.上节内容补充

2.string的模拟实现

2.1传统的写法

2.2现代写法模拟实现

2.3 string 数据插入等实现

2.4运算符的重载

3.所有代码(留存)


1.上节内容补充

1.string是可以进行比较的

#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	string s2("iostream");
	//两个string比较
	cout << (s1 > s2) << endl;//第一个字符h<i所以 输出0
	//string和字符串比较(很少这样用,一般都是使用两个对象(两个string))
	cout << (s1 < "iii") << endl;
	cout << ("ccc" < s1) << endl;
	return 0;
}

2.字符串转整形,长整型等类型

stoi

#include<iostream>
#include<string>
using namespace std;
int main()
{
	string s1("1234567");
	int val = stoi(s1);
	cout << val << endl;


	//int base=10代表转成10进制的形式
	size_t sz = 0;//sz会返回一共成功转换了几个字符
	int val1 = stoi("223",&sz);
	cout << val1 << endl;
	cout << sz << endl;
	return 0;
}

3.整形,浮点型等转字符串

 

to_string 

#include<iostream>
#include<string>
using namespace std;
int main()
{
	string str=to_string(3.14);//默认保留6位小数
	cout << str << endl;
	return 0;
}

4.练习题

1.回文字符串

力扣https://leetcode-cn.com/problems/valid-palindrome/

class Solution {
public:

	bool IsLetterOrNumber(char s)
	{
		if ((s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z'))
			return true;
		if (s >= '0' && s <= '9')
			return true;

		return false;
	}
	char my_tolower(char str)
	{
		if (str >= 'A' && str <= 'Z')
		{
			str += 32;
		}
		return str;
	}
	bool isPalindrome(string s) {
		int begin = 0;
		int end = s.size() - 1;
		while (begin<end)
		{
			while (begin<end && !IsLetterOrNumber(s[begin]))
			{
				begin++;
			}
			while (begin<end && !IsLetterOrNumber(s[end]))
			{
				end--;
			}
			if (my_tolower(s[begin])!=my_tolower(s[end])) 
            //等价于if(tolower(s[begin])!=tolower(s[end])),tolower 是C语言库函数
            //还有一个toupper 正好两个为一对
				return false;

			begin++;
			end--;
		}
		return true;
	}
};

也可以 在bool isPalindrome(string s) 函数一开始,把stirng类的字符串转成统一的大写或小写。

// 先小写字母转换成大写,再进行判断
 for(auto& ch : s)
 {
 if(ch >= 'a' && ch <= 'z')
 ch -= 32;
 }

 2.字符串相加

力扣https://leetcode-cn.com/problems/add-strings/submissions/

class Solution {
public:
    string addStrings(string num1, string num2) {
        int end1=num1.size()-1;
        int end2=num2.size()-1;
        int next=0;//进位
        string temp;
        while(end1>=0 || end2>=0)
        {
            int x1=0,x2=0;
            if(end1>=0)
            {
                    x1=num1[end1]-'0';
                    end1--;
            }
                
            if(end2>=0)
            {
                 x2=num2[end2]-'0';
                 end2--;
            }
               
         
            int ret=x1+x2+next; 
            if(ret>9)
            {
                next=1;
                ret-=10;
            }
            else
            {
                next=0;
            }

            temp+=(ret+'0');//尾插

        }
        if(next==1)
        {
             temp+='1';
        }
       reverse(temp.begin(),temp.end());//逆置
        
        return temp;
    }
};

2.string的模拟实现

2.1传统的写法

1.string的基本框架:

	
namespace str //命名空间,为了防止和string库的命名冲突
{

	class string
	{
	public:

        //成员函数

	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};

}

2.成员函数 

2.1构造函数

string库里的构造函数,我不传参数进行初始化,也就是调用默认构造函数:

#include<iostream>
using namespace std;
int main()
{
	string s1;//不给参数
	cout << s1 << endl;
	return 0;
}

发现打印的是空字符串: 

所以默认构造函数的实现:

string()
			:_str(new char[1])
			, _size(0)
			,_capacity(0)
		{
			_str[0] = '\0';
		}

需要注意的是:

这里不能写_str(nullptr) 有个函数c_str是返回字符串的起始想打印字符串,会发现会报错。这里必须是new char[ ]为了与析构函数相对应 。

改进构造函数:

//构造函数
		string(const char* s = "") //空字符串 有'\0'
			:_size(strlen(s))//有效字符的个数
			, _capacity(_size) //能够存储有效字符的空间大小。不包括'\0'
		{
			_str = new char[_capacity+1];//开空间的时候,要给'\0'开辟一个空间
			strcpy(_str,s);
		}

2.2析构函数

//析构函数
		~string()
		{
			delete[] _str;
			_str =nullptr;
		}

2.3拷贝构造函数

//拷贝构造,必须深拷贝
		string(const string& s)
			:_size(s._size)
			, _capacity (s._capacity)
		{
			_str = new char[_capacity + 1];
			strcpy(_str,s._str);
			
		}

2.4赋值重载

需要注意赋值重载是需要深拷贝的。

	//赋值重载
		string& operator=(const string&s)
		{
			if (this != &s) //注意:自己给自己赋值时
			{
				//先申请,不要一上来就销毁,要是申请失败了,原数据也给销毁了。
				char*temp = new char[strlen(s._str) + 1];
				strcpy(temp, s._str);
				delete[] _str; //释放构造时的空间
				_str = temp;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}

2.5[ ]重载

需要注意:[ ]是断言

char& operator[](size_t pos)
		{
			assert(pos<_size);//[]是断言,at是抛异常
			return _str[pos];
		}
const char& operator[](size_t pos)const
		{
			assert(pos<_size);//断言
			return _str[pos];
		}

2.6 size() 和 c_str()

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

size_t size()const
		{
			return _size;
		}

2.7迭代器

		typedef char* iterator;//迭代器

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

		typedef const char* const_iterator;//const 迭代器

		const_iterator begin()const
		{
			return _str;
		}
		const_iterator end()const
		{
			return _str + _size;
		}

2.8 String.h 整体的代码

#include<iostream>
#include<cassert>
using namespace std;


namespace str
{
	class string
	{
	public:
		//构造函数
		string(const char * s="")
			:_size(strlen(s))
			,_capacity(_size)
		{
			_str = new char[_capacity+1];
			strcpy(_str,s);
		}

		//拷贝构造函数
		//s2(s1)
		string(const string&s)
			:_size(s._size)
			, _capacity(s._capacity)
		{
			_str = new char[_capacity + 1];//开辟时是需要开辟capacity+1 为'\0'开辟空间
			strcpy(_str,s._str);
		}

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

		//c_str函数
		const char* c_str()const
		{
			return _str;
		}
		//size()函数
		size_t size()const 
		{
			return _size;
		}

		//赋值运算符重载
		string& operator=(const string& s)
		{
			if (this != &s)
			{
				char*tmp = new char[strlen(s._str)+1];
				strcpy(tmp,s._str);
				delete[]_str;
				_size = s._size;
				_capacity = s._capacity;
				_str = tmp;
			}
			return *this;
		}
		//[ ]重载
		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;
		}


	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};

	void test1()
	{
		//构造函数测试
		string s;
		cout << s.c_str() << endl;
		string s1("hello world");
		cout << s1.c_str() << endl;
		//拷贝构造测试
		string s2(s1);
		cout << s2.c_str() << endl;
		//赋值重载测试
		string s3;
		s3 = s2;
		cout << s3.c_str() << endl;
		//[ ]重载测试
		for (size_t i = 0; i < s3.size(); i++)
		{
			s3[i] += 1;//修改
		}
		cout << s3.c_str()<<endl;
		//迭代器测试
		string::iterator it = s3.begin();
		while (it != s3.end())
		{
			*it -= 1;
			cout << *it;
			it++;
		}
		cout << endl;
		//const 迭代器只读
		string::const_iterator it1 = s3.begin();
		while (it1!=s3.end())
		{
			cout << *it1;
			it1++;
		}
		cout << endl;
		//范围for底层是调用迭代器的
		for (auto e : s3)
		{
			cout << e;
		}
		cout << endl;
	}
	
}

代码测试: 

#include "String.h"
int main()
{	
	str::test1();
	return 0;
}

小插曲:

其实范围for的底层是调用迭代器,编译器会直接把范围for变成迭代器:

我把迭代器begin函数改成大写的。再使用范围发现标红报错,所以范围for的底层调用的是迭代器。

2.2现代写法模拟实现

swap函数:下面会用到先铺垫一下

C++中提供了一个string成员swap:

实现的方式是去调用std里的全局swap。 

void swap(string&s)
		{
			//swap最好应用于内置类型的交换
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

为什么会有2个swap,这两个直接的区别是什么?

int main()
{	
	string s1("hello world");
	string s2;
	s1.swap(s2);//string
	swap(s1, s2);//全局
	return 0;
}

首先string中底层是去调用的全局swap,但是交换时仅仅是交换了成员变量,而全局的swap在进行两个对象的交换时会发生一次深度拷贝构造,和2次的深度赋值重载的调用,其代价是非常大的,会影响执行效率,所以推荐全局的swap用来交换内置类型。

现代写法讲解:

其实现代写法是复用的一个过程:

1.构造函数还是不变的,因为下面需要复用,所以列出来方便看

	//构造函数
		string(const char * s="")
			:_size(strlen(s))
			,_capacity(_size)
		{
			_str = new char[_capacity+1];
			strcpy(_str,s);
		}

2.拷贝构造函数的现代写法

string(const string& s)
			:_str(nullptr)//这里需要置空,析构函数delete对nullptr做了处理的,也可以自己加上判断
			//如果不置空会析构随机地址,会报错
			, _size(0) //最好都初始化一下,避免不必要的麻烦
			, _capacity(0)
		{
			string tmp(s._str);//调用构造函数
			swap(tmp);
		}

拷贝构造讲解:

string s1("hello world");
string s2(s1);

使用s1拷贝构造s2, s2.string(s1) ,先把s2的_str 置为空,_size和_capacity置为0。使用s1的中的_str 也就是字符串,来构造一个新的对象tmp,此时的tmp已经和s1的内容一样,利用swap函数,分别交换s2和tmp 中的_str,_size,_capacity。对于_str 交换的是地址。执行完swap该函数马上就结束了,此时的临时对象tmp会去调用析构函数,清理资源正好把s2原始空间或数据清理完成。

3.析构函数 

析构函数也是可以不变的,析构函数本身对nullptr做了处理的,也可以自己处理。比如:

	//析构函数
		~string()
		{
            //这个if语句可以不加,delete内部已经这么处理过了,或者更全面
			if (_str != nullptr)
			{
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0;
			}
			
		}

4.赋值重载

赋值重载直接复用的拷贝构造。思路和拷贝构造差不多。

	//赋值运算符重载现代写法
		string& operator=(const string &s)
		{
			if (this != &s)
			{
				string tmp(s);//调用拷贝构造函数
				swap(tmp);
			}
			return *this;
		}

改进:

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

讲解:

string s1("hello world");
string s2;
s2=s1;

s2=s1 实际上:s2.operator(s1) ,先是拷贝构造了一个s对象,然后利用swap函数进行s2和s指针和值的交换,s对象是一个局部对象,在赋值重载函数结束时会去调用析构函数,正好swap已经完成了,此时s的内容都是s1之前的内容,整好帮助s清理之前的空间。这个赋值重载也不用检查自己给自己赋值,因为指向的空间都不一样。

2.3 string 数据插入等实现

1.reserve扩容函数:

需要注意开辟空间时是需要多开辟一个,为了存储'\0'。_capacity是能够存储有效字符的容量

void reserve(size_t n)
		{
			//加这个判断是为了和string中的reserve对应
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp,_str);
				delete[]_str;
				_str = tmp;
				_capacity = n;
			}
		}

2.push_back函数实现

	void push_back(char ch)
		{
			if (_size == _capacity)
			{
				reserve(_capacity==0? 4 : _capacity*2);
				//为了防止上来_capacity是0 string s2; s2.push_back('c');这样会报错
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}

3.append函数实现

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

4.+=重载

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

5.resize函数

了解一下resize的脾气:

int main()
{	
	string s1("hello world");
	s1.resize(2);//当申请的空间小于_size
	cout << s1.c_str() << endl;
	string s2("hello world");
	s2.resize(20);//申请空间大于_size,没有初始化
	cout << s2.c_str() << endl;
	string s3("hello world");
	s3.resize(20,'c');申请空间大于_size,并初始化
	cout << s3.c_str() << endl;
	return 0;
}

resize分为3中情况: 

1.申请的空间小于_size 只保留了申请空间的有效字符

2.申请的空间大于_size 没有初始化,会在后面多出来的空间填'\0',_size也变化了。 在这里的'\0'也是有效数据。但是打印不出来而已。

s2原始的数据:

resize后:

3. 申请的空间大于_size 并且初始化了。

resize的模拟实现:

主要注意3种情况:

	void resize(size_t n, char ch = '\0')
		{
			if (n <= _size)
			{
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				if (n>_capacity)//当大于_capacity时进行扩容
				{
					reserve(n);
				}
				memset(_str+_size,ch,n-_size);
				_size = n;
				_str[_size] = '\0';
			}
		}

 6.find查找字符和字符串

1.查找字符

	size_t find(char ch)
		{
			for (size_t i = 0; i < _size; i++)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos; //在类中定义了一个static const 变量 并赋值给了-1
		}

在成员变量中增加了一个无符号静态变量npos:

2.查找字符串

	size_t find(const char* str, size_t pos)
		{
			const char* tmp=strstr(_str+pos,str);
			if (tmp == nullptr)
			{
				return npos;
			}
			return tmp - _str;  //指针-指针
		}

7.insert 函数

string& insert(size_t pos, char ch)
		{
			assert(pos<=_size);
			if (_size == _capacity)
			{
				reserve(_capacity==0 ? 4: _capacity*2);
			}

			for (size_t i = _size+1; i > pos; i--)
			{
				_str[i] = _str[i-1];
			}
			_str[pos] = ch;
			++_size;
			return *this;
			
		}
		
string& insert(size_t pos, const char*str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(len+_size);
			}
			size_t end = _size + len;
			while (end>=pos+len)
			{
				_str[end] = _str[end-len];
				end--;
			}
			strncpy(_str + pos, str, len);//不能使用strcpy会自己加\0
			_size += len;
			return *this;
		}

8.erase函数

需要注意3种情况:
1.默认情况下npos,是删除pos位置向后的所有数据

2.pos位置后面的字符个数不够len,也是一样是删除pos位置向后的所有数据

3.比如我有7个数据,我删除5位置处向后的1个字符。pos+len<_size。

string& erase(size_t pos, size_t len=npos)
		{
			//erase只清理数据,不清理容量
			assert(pos<_size);
			if (len == npos || pos+len >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str+pos ,_str+pos+len);
				_size -= len;
			}
			return *this;
		}

2.4运算符的重载

运算符的重载不是友元函数,也不是成员函数,而是定义在自己命名空间str中的全局函数。它们主要是通过我们自己定义的string类里的成员函数进行访问私有成员变量的。

1. <运算符重载

while结束时需要注意3种情况

//"abcd"  "abcd"  //false 同时结束
//"abcd"  "abcde" //true  s1结束,s2没结束
//"abcd"   "abc"  //false s1没结束 ,s2结束

bool operator<(const string& s1, const string&s2)
	{
		size_t i1 = 0;
		size_t i2 = 0;
		
		while (i1<s1.size() && i2<s2.size())
		{
			if (s1[i1] < s2[i2])
			{
				return  true;
			}
			else if (s1[i1]>s1[i2])
			{
				return false;
			}
			i1++;
			i2++;
		}
		分为3种情况
		//"abcd"  "abcd"  //false 同时结束
		//"abcd"  "abcde" //true  s1结束,s2没结束
		//"abcd"   "abc"  //false s1没结束 ,s2结束
		return i2 < s2.size() ? true : false;

		//等价于:return strcmp(s1.c_str(),s2.c_str()) < 0;
	}

2.==重载

bool operator==(const string& s1,const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) == 0;
	}

3.其他运算符都是复用

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

4.流提取和流插入 

//流提取和流插入
	//流提取
	istream& operator>>(istream& in, string& s)
	{
		char ch=in.get();
		while (ch!=' ' &&  ch!= '\n')
		{
			s += ch;
			ch = in.get();
		}
		return in;
	}
	//流插入
	ostream& operator<<(ostream& out, const string& s)
	{
		
		for (auto e: s)
		{
			out << e;
		}
		
		/*for (size_t i = 0; i < s.size(); i++)
		{
			out << s[i];
		}*/

		//不要写成 我数据第一个就是\0 就打印不出后面的数据。
		// out << s.c_str();

		return out;
	}

3.所有代码(留存)

String.h:

#include<iostream>
#include<cassert>
using namespace std;


namespace str
{
	class string
	{
	public:
		//构造函数
		string(const char * s="")
			:_size(strlen(s))
			,_capacity(_size)
		{
			_str = new char[_capacity+1];
			strcpy(_str,s);
		}

		//拷贝构造函数传统写法
		//s2(s1)
		//string(const string&s)
		//	:_size(s._size)
		//	, _capacity(s._capacity)
		//{
		//	_str = new char[_capacity + 1];//开辟时是需要开辟capacity+1 为'\0'开辟空间
		//	strcpy(_str,s._str);
		//}
		void swap(string&s)
		{
			//swap最好应用于内置类型的交换
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		//拷贝构造函数现代写法
		string(const string& s)
			:_str(nullptr)//这里需要置空,析构函数对nullptr做了处理的,也可以自己加上判断
			//如果不置空会析构随机地址,会报错
			, _size(0) //最好都初始化一下,避免不必要的麻烦
			, _capacity(0)
		{
			string tmp(s._str);//调用构造函数
			swap(tmp);
		}


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

		//c_str函数
		const char* c_str()const
		{
			return _str;
		}
		//size()函数
		size_t size()const 
		{
			return _size;
		}

		//赋值运算符重载
	/*	string& operator=(const string& s)
		{
			if (this != &s)
			{
				char*tmp = new char[strlen(s._str)+1];
				strcpy(tmp,s._str);
				delete[]_str;
				_size = s._size;
				_capacity = s._capacity;
				_str = tmp;
			}
			return *this;
			}*/
		//赋值运算符重载现代写法
		string& operator=(const string &s)
		{
			if (this != &s)
			{
				string tmp(s);//调用拷贝构造函数
				swap(tmp);
			}
			return *this;
		}
		/*string& operator=(string s)
		{
			swap(s);
			return *this;
		}*/

		
		//[ ]重载
		char& operator[](size_t pos)
		{
			assert(pos<_size);//断言
			return _str[pos];
		}

		const char& operator[](size_t pos)const
		{
			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;
		}


		void reserve(size_t n)
		{
			//加这个判断是为了和string中的reserve对应
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp,_str);
				delete[]_str;
				_str = tmp;
				_capacity = n;
			}
		}
		void push_back(char ch)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
				//为了防止上来_capacity是0 string s2; s2+='c';这样会报错
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}

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

		void resize(size_t n, char ch = '\0')
		{
			if (n <= _size)
			{
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				if (n>_capacity)//当大于_capacity时进行扩容
				{
					reserve(n);
				}
				memset(_str+_size,ch,n-_size);
				_size = n;
				_str[_size] = '\0';
			}
		}

		size_t find(char ch)
		{
			for (size_t i = 0; i < _size; i++)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}
		size_t find(const char* str, size_t pos)
		{
			const char* tmp=strstr(_str+pos,str);
			if (tmp == nullptr)
			{
				return npos;
			}
			return tmp - _str;
		}

		string& insert(size_t pos, char ch)
		{
			assert(pos<=_size);
			if (_size == _capacity)
			{
				reserve(_capacity==0 ? 4: _capacity*2);
			}

			for (size_t i = _size+1; i > pos; i--)
			{
				_str[i] = _str[i-1];
			}
			_str[pos] = ch;
			++_size;
			return *this;
			
		}
		
		string& insert(size_t pos, const char*str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(len+_size);
			}
			size_t end = _size + len;
			while (end>=pos+len)
			{
				_str[end] = _str[end-len];
				end--;
			}
			strncpy(_str + pos, str, len);//不能使用strcpy会自己加\0
			_size += len;
			return *this;
		}


		string& erase(size_t pos, size_t len=npos)
		{
			//erase只清理数据,不清理容量
			assert(pos<_size);
			if (len == npos || pos+len >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str+pos ,_str+pos+len);
				_size -= len;
			}
			return *this;
		}





	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		static const size_t npos;
	};
	const size_t string::npos = -1;


	//运算符重载
	//两个对象比较大小
	bool operator<(const string& s1, const string&s2)
	{
		size_t i1 = 0;
		size_t i2 = 0;
		
		while (i1<s1.size() && i2<s2.size())
		{
			if (s1[i1] < s2[i2])
			{
				return  true;
			}
			else if (s1[i1]>s1[i2])
			{
				return false;
			}
			i1++;
			i2++;
		}
		分为3种情况
		//"abcd"  "abcd"  //false 同时结束
		//"abcd"  "abcde" //true  s1结束,s2没结束
		//"abcd"   "abc"  //false s1没结束 ,s2结束
		return i2 < s2.size() ? true : false;

		//等价于:return strcmp(s1.c_str(),s2.c_str()) < 0;
	}

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

	//流提取和流插入
	//流提取
	istream& operator>>(istream& in, string& s)
	{
		char ch=in.get();
		while (ch!=' ' &&  ch!= '\n')
		{
			s += ch;
			ch = in.get();
		}
		return in;
	}
	//流插入
	ostream& operator<<(ostream& out, const string& s)
	{
		
		for (auto e: s)
		{
			out << e;
		}
		
		/*for (size_t i = 0; i < s.size(); i++)
		{
			out << s[i];
		}*/

		//不要写成 我数据第一个就是\0 就打印不出后面的数据。
		// out << s.c_str();

		return out;
	}

	void test1()
	{
		//构造函数测试
		string s;
		cout << s.c_str() << endl;
		string s1("hello world");
		cout << s1.c_str() << endl;
		//拷贝构造测试
		string s2(s1);
		cout << s2.c_str() << endl;
		//赋值重载测试
		string s3;
		s3 = s2;
		cout << s3.c_str() << endl;
		//[ ]重载测试
		for (size_t i = 0; i < s3.size(); i++)
		{
			s3[i] += 1;//修改
		}
		cout << s3.c_str()<<endl;
		//迭代器测试
		string::iterator it = s3.begin();
		while (it != s3.end())
		{
			*it -= 1;
			cout << *it;
			it++;
		}
		cout << endl;
		//const 迭代器只读
		string::const_iterator it1 = s3.begin();
		while (it1!=s3.end())
		{
			cout << *it1;
			it1++;
		}
		cout << endl;
		//范围for底层是调用迭代器的
		for (auto e : s3)
		{
			cout << e;
		}
		cout << endl;
	}
	void test2()
	{
		string s1("hello world");
		string s2(s1);
		cout << s2.c_str() << endl;
		string s3;
		s2 = s2;
		cout << s3.c_str() << endl;
	}


	void test3()
	{
		/*string s1("hello world");
		s1.push_back('c');
		cout << s1.c_str() << endl;
		s1.append("abcdefg");
		cout << s1.c_str() << endl;

		string s2;
		s2 += "hello world";
		s2.insert(11, 'a');
		cout << s2.c_str() << endl;*/
		string s3("aaaa");
		s3.insert(4,"hello world");
		cout << s3.c_str() << endl;
		s3.erase(5,2);
		cout << s3.c_str() << endl;
	}

	void test4()
	{
		string s2("hello");
		s2.insert(0, "ab");
		cout << s2.c_str() << endl;
	}

	void test5()
	{
		string s2;
		string s1;
		cin>>s2>>s1;
		cout << s2 << endl;
		cout << s1 << endl;
	}
}



main.c: 

#include "String.h"
int main()
{	
	str::test5();

	return 0;
}
举报

相关推荐

string模拟实现

string模拟实现:

string【2】模拟实现string类

string的模拟实现

c++ string模拟实现

C++string的模拟实现

【C++】string的模拟实现

0 条评论