string类及相关函数的实现

Posted 在下赵某人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了string类及相关函数的实现相关的知识,希望对你有一定的参考价值。

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

namespace zzd
{
	class string
	{
	public:
		//默认构造一、 string();
		string()
			:_str(new char[1])
			,_size(0)
			,_capacity(0)
		{
			_str[0] = '\\0';//就算没数据,_str也要指向一个new出来的空间并且以 '\\0' 结束


		}

		//默认构造二、 将构造函数 string(const char* s); 给个缺省值实现 string(const char* s = "");
		//string(const char* s = "")//若未传参数,则s是一个空串,-->strlen(s) == 0
		//	:_str(new char[strlen(s) + 1])
		//	, _size(strlen(s))
		//	, _capacity(strlen(s))
		//{
		//	strcpy(_str, s);
		//}
		
		//构造函数string s1("hallo");
		string(const char* s)
			:_str(new char[strlen(s) + 1])
			,_size(strlen(s))
			,_capacity(strlen(s))
		{
			strcpy(_str, s);
			//_str[strlen(s)] = '\\n';--->用不着:strcpy把从src地址开始且含有’\\0’结束符的字符串复制到以dest开始的地址空间,返回值的类型为char*
		}
		//resize的函数实现
		void resize(size_t n, char c = '\\0')
		{
			int sz = strlen(_str);
			if (_capacity < n)
			{
				reserve(2 * n);
			}
			if (n < _size)
			{
				_size = n;
				_str[_size] = '\\0';
				return;
			}
			_size = n;
			for (int i = sz; i < _size; i++)
			{
				_str[i] = c;
			}
			_str[_size] = '\\0';
		}
		//swap的函数实现(不能叫重载,因为不在同一个命名空间)
		void swap(string& s)
		{
			::swap(_str, s._str);// ::是用来指定这里的swap是全局域的swap
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}
		//拷贝构造现代写法string s2(s1);
		string(const string& s)
			:_str(nullptr)
		{
			string tmp(s._str);//s._str 是字符串类型,这里调用了构造函数 string(const char* s);
			swap(tmp);//要用第一种构造函数构造一个临时变量,用 临时变量的_str 和 this->_str 交换,
			          //该函数结束后tmp调析构函数会将里面的资源释放,故刚开始需将_str初始化为nullptr,防止delete一个随机值。
		}

		//赋值操作符传统写法
		//string& operator=(string& s)
		//{
		//	if (this != &s)
		//	{
		//		char* tmp = new char[strlen(s._str) + 1];
		//		delete[] _str;
		//		_str = tmp;
		//		strcpy(_str, s._str);
		//		_size = strlen(s._str);
		//		_capacity = strlen(s._str);
		//	}
		//	return *this;
		//}
		
		//赋值操作符现代写法
		string& operator=(string s)//用了传值传参(实际相当于调用拷贝构造 实现了 深拷贝)
		{
			swap(s);//交换 s与*this 的数据
			return *this;
		}
		//实现size()接口
		int size() const //函数内部不进行修改,所以最好把const带上,这样const对象与非const对象都可以调用
		{
			return _size;
		}
		//实现capacity()接口
		int capacity() const
		{
			return _capacity;
		}
		//[]操作符重载 可读可写
		char& operator[](int i)
		{
			assert(i < _size );//下标合法性的检查(检查是否越界访问)
			return _str[i];
		}
		//[]操作符重载 只可读
		const char& operator[](int i) const
		{
			assert(i < _size);
			return _str[i];
		}
		//尾插字符函数
		void PushBack(char c)
		{
			if (_size == _capacity)
			{
				int new_capacity = _capacity == 0 ? 4 : 2 * _capacity;
				reserve(new_capacity);
			}
			_str[_size] = c;
			_size++;
			_str[_size] = '\\0';
		}
		//尾插字符串函数
		void append(const char* s)
		{
			if (_size + strlen(s) >= _capacity)
			{
				reserve(2 * _size + strlen(s));
			}
			strcpy(_str + _size, s);
			_size += strlen(s);
		}
		//扩容函数
		void reserve(int capacity)
		{
			if (capacity > _capacity)
			{
				char* tmp = new char[capacity + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = nullptr;
				::swap(_str, tmp);
				_capacity = capacity;
			}
		}		
		//+=操作符重载(插字符)
		string&  operator+=(const char c)
		{
			PushBack(c);
			return *this;
		}
		//+=操作符重载(插字符串)
		string& operator+=(const char* s)
		{
			append(s);
			return *this;
		}
		// + 操作符重载(char)
		string operator+(char c)
		{
			string tmp(*this);
			tmp += c;
			return tmp;
		}
		// + 操作符重载(char*)
		string operator+(const char* s)
		{
			string tmp(*this);
			tmp += s;
			return tmp;
		}
		//c_str()接口的实现
		char* c_str()
		{
			return _str;
		}
		//定义迭代器
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			char* tmp = _str + _size;
				return tmp; //指向最后一个有效数据的后面位置
		}
		//定义迭代器(const 版本)
		typedef const char* const_iterator;
		const_iterator begin() const
		{
			return _str;
		}
		const_iterator end() const
		{
			char* tmp = _str + _size;
			return tmp; //指向最后一个有效数据的后面位置
		}
		//遍历打印一、
		void print() 
		{
			cout << "法一、:";  //按_size来打印('\\0'也会打印,只不过不显示)
			for (int i = 0; i < _size; i++) 
			{
				cout << _str[i];
			}
			cout << endl;
			
			cout << "法二、:"; //有缺陷,遇到 '\\0' 会停止打印,不会按_size来打印
			cout << c_str() << endl;  


			cout << "法三、:"; //迭代器打印法
			iterator it = begin();
			while (it != end())
			{
				cout << *it << ' ';
				it++;
			}
			cout << endl;
		}
		//insert(size_t pos, char c)函数实现
		void insert(size_t pos, char c)
		{
			assert(pos <= _size);
			//判断是否扩容
			if (_size == _capacity)
			{
				int new_capacity = _capacity == 0 ? 4 : 2 * _capacity;
				reserve(new_capacity);
			}
			//从后往前移
			for (int i = _size; i > pos; i--)
			{
				_str[i] = _str[i - 1];
			}
			_size++;
			//最后要插入'\\0'
			_str[_size] = '\\0';
			_str[pos] = 'c';
		}
		//insert(size_t pos, char* s)函数实现
		void insert(size_t pos,const char* s)
		{
			//assert(pos <= _size);
			//int sz = strlen(s);
			//if (sz == 0)
			//{
			//	return;
			//}
			判断是否扩容
			//if (_size + sz > _capacity)
			//{
			//	int new_capacity = _capacity == 0 ? 4 : 2 * (_size + sz);
			//	reserve(new_capacity);
			//}
			从后往前移
			//for (int i = _size + sz - 1; i >= pos + sz; i--)
			//{
			//	_str[i] = _str[i - sz];
			//}
			//char c = _str[pos + sz];
			//strcpy(_str + pos , s);//strcpy会将'\\0'也拷贝过去
			//_str[pos + sz] = c;
			//_size += sz;
			最后要插入'\\0'
			//_str[_size] = '\\0';
			//----------------------实现方式二----------------------//
			assert(pos <= _size);
			size_t len = strlen(s);
			//处理空串情况
			if (len == 0)
			{
				return;
			}
			//判断增容
			if (_size + len > _capacity)
			{
				reserve((_size + len) * 2);
			}
			//从后往前拷贝,空出插入的位置
			size_t end = _size + len;
			while (end >= pos + len)
			{
				_str[end] = _str[end - len];
				end--;
			}
			//将数据插入
			for (int i = 0; i < len; i++)
			{
				_str[pos + i] = s[i];
			}
		}
		//erase()函数的实现
		void erase(int pos, size_t n = npos)
		{
			//判断下标合法性
			assert(pos < _size);
			if (n == npos || n >= _size - 1)
			{
				_size = pos;
				_str[pos] = '\\0';
				return;
			}
			strcpy(_str + pos, _str + n + 1);
		}
		//clear()函数的实现
		void clear()
		{
			_str[0] = '\\0';
			_size = 0;


		}
		//析构函数
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
	private:
		char* _str;
		int _size;
		int _capacity;
		static size_t npos; //声明了静态成员变量但未定义
	};
	//定义、初始化静态成员变量
	size_t string::npos = -1;//定义了静态成员变量,同时初始化(不初始化也可以通过编译)
	//非成员函数的print()实现
	void print(const string& str)
	{
		for (int i = 0; i < str.size(); i++)
		{
			cout << str[i]; //这里调用的是 只可读的[]操作符重载
			// str[i]++; ---> 该表达式不合法因为调用的是只可读[]重载
		}
		cout << endl;
		迭代器
		//for (auto a : str)
		//{
		//	cout << a;
		//}
		//cout << endl;
	}
	
	//">>"和"<<"的重载并不一定要设置成友元,
	//因为调用公有函数来访问私有成员就可以不设友元
	
	// <<操作符重载
	ostream& operator<<(ostream& _cout, const string& s)
	{
		print(s);
		return _cout;
	}
	// >>操作符重载
	istream& operator>>(istream& _cin, string& s)
	{
		s.clear();
		char ch;
		ch = _cin.get();//cin是拿不到' '和'\\n'的,会自动忽略,会认为是输入两个值之间的间隔。要用cin这个类里的get();	(std::istream::get)
		while (ch != ' ' && ch != '\\n')
		{
			s += ch;
			ch = _cin.get();//--->可以看做get()是cin的成员函数
		}
		return _cin;
	}
	//getline()函数的实现
	istream& getline(istream& _cin, string& s)
	{
		s.clear();
		char ch;
		ch = _cin.get();//输入的数据未取完的暂时存在缓存区
		while (ch != '\\n')
		{
			s += ch;
			ch = _cin.get();
		}
		return _cin;
	}
	// == 操作符重载
	bool operator==(string& s1, string& s2)
	{
		//s1和s2的size()都不同则直接返回false
		if (s1.size() != s2.size())
		{
			return false;
		}
		//s1和s2的size()相同的情况
		int i = 0;
		while (i < s1.size())
		{
			if (s1[i] != s2[i])
			{
				return false;
			}
			i++;
		}
		return true;
	}
	// > 操作符重载
	bool operator>(string& s1, string& s2)
	{
		int i1 = 0, i2 = 0;
		while ((i1 < s1.size()) && (i2 < s2.size()))
		{
			if (s1[i1] > s2[i2])
			{
				return true;
			}
			else if (s1[i1] == s2[i2])
			{
				return false;
			}
			else
			{
				i1++;
				i2++;
			}	
		}
		if (i1 == s1.size())
		{
			return false;
		}
		else
		{
			return true;
		}
	}
	// != 操作符重载
	bool operator!=(string& s1, string& s2)
	{
		return !(s1 == s2);
	}
	// < 操作符重载
	bool operator<(string& s1, string& s2)
	{
		return !((s1 == s2) || (s1 > s2));
	}
	// >= 操作符重载
	bool operator>=(string& s1, string& s2)
	{
		return (s1 > s2) || (s1 == s2);
	}
	// <= 操作符重载
	bool operator<=(string& s1, string& s2)
	{
		return (s1 < s2) || (s1 == s2);
	}
	//测试函数
	void test1()
	{
		string s1("hello");
		string s2(s1);
		string s3("world!");
		s3 = s1;
		s3.PushBack(' ');
		s3.append("world!");
		s1 += ' ';
		s1 += "world!";
		s1.print();
	}
	void test2()
	{
		string s1;
		string s2("hello");
		s2.resize(2);
		s2.resize(5, 'a');
		s2.resize(20);
		s2[17] = 'x';
		cout << "print()函数打印" << endl;
		s2.print();
		cout << "while迭代器遍历" << endl;
		string::iterator it = s2.begin();// (string::)作用是指定类域 
		                                 // (iterator)是变量it的类型,这里实际是char*.
		                                 // ( s1.begin(); )这个是调用对象s1的成员函数
		while (it != s2.end())
		{
			cout << *it << ' ';
			it++;
		}
		cout << endl;
		cout << "范围for遍历" << endl;
		for (auto c : s2)
		{
			cout << c << ' '; //一个容器只要按规范支持迭代器,就支持范围for
		}
		cout << endl;
	}
	void test3()
	{
		string s1("15678");
		print(s1);
		s1.insert(1, "234");
		print(s1);
	}
	void test4()
	{
		string s1("hello");
		//s1.erase(0, 1);
		cin >> s1;
		print(s1);
	}
	void test5()
	{
		string s1("hello");
		//getline(cin, s1);
		print(s1);
		string s2("hello");
		string s3(s2);
		s3 += 'c';
		s1 == s2;
		s1 > s3;
	}
	void test6()
	{
		string s1("hello");
		string s2(s1);
		string s3 = s1 + 'a';
		string s4 = s2 + " world!";
	}
}


int main()
{
	//zzd::test1();
	//zzd::test2();
	//zzd::test3();
	//zzd::test4();
	//zzd::test5();
	zzd::test6();
	return 0;
}

以上是关于string类及相关函数的实现的主要内容,如果未能解决你的问题,请参考以下文章

python中的抽象基类及相关用途

Java之常用类及方法

快速上手kotlin接口抽象类及泛型

快速上手kotlin接口抽象类及泛型

Map的常用实现类及Entry的用法

基于Java+HttpClient+TestNG的接口自动化测试框架------ 测试用函数接口类及实现类