【C++学习笔记】----模拟实现string类及成员函数(详解)

1.简介

string类是表示字符串的字符类,是一块连续的空间存储字符串,并且可以通过统一接口,实现插入,删除,尾插,查找,迭代器遍历等一系列操作。

2.代码展示

#define _CRT_SECURE_NO_WARNINGS 1;
#include
#include
using namespace std;
namespace xff {
	class string {
	public:
		typedef char* iterator;
		//迭代器
		iterator begin() {
			return _str;
		}
		iterator rbegin() {	//最后一个字符
			return _str+_size-1;
		}
		iterator end() {
			return _str + _size;
		}
		iterator rend() {	//第一个字符的前一个
			return --_str;
		}
		//构造函数
		string(const char* str=""){
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		//拷贝构造
		string(const string& s)
				:_str(nullptr)
				,_size(0)
				,_capacity(0)
		{
			string tmp(s._str);
			this->swap(tmp);
		}
		//析构函数
		~string(){
			if (_str) {
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0; 
			}
		}
		//=
		string operator=(string s) {
			this->swap(s);
			return *this;
		}
		//size
		size_t  size()const {
			return _size;
		}
		//capacity
		size_t capacity()const {
			return _capacity;
		}
		//[]
		char& operator[](size_t index) {
			assert(index < _size);
			return _str[index];
		}
		//[]const
		const char& operator[](size_t index)const {
			assert(index < _size);
			return _str[index];
		}
		//c_str
		const char* c_str() {
			return _str;
		}
		void swap( string& s) {
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		//判断是否为空
		bool empty() {
			if (_size == 0) {
				return true;
			}
			return false;
		}
		//reserve预留空间
		void reserve(size_t num) {
			if (num > _capacity) {
				char* newstr = new char[num + 1];
				strcpy(newstr, _str);
				delete[] _str;
				_str = newstr;
				_capacity = num;
			}
		}
		//push_back
		void push_back(const char ch) {
			if (_size == _capacity) {
				size_t newcapacity = _capacity == 0 ? 2 : 2*_capacity;
				reserve(newcapacity);
			}
			_str[_size++] = ch;
			_str[_size] = '\0';
		}
		//operator+=()字符
		 string& operator+=(const char ch) {
			this->push_back(ch);
			return *this;
		}
		 //operator+=()字符串
		 string& operator+=(const char* str) {
			this->append(str);
			return *this;
		}
		//append加字符串
		void append(const char* str = "") {
			size_t len = strlen(str);
			if (len + _size > _capacity) {
				/*size_t newcapacity = _capacity = len + _size;
				char* newstr = new char[newcapacity + 1];
				strcpy(newstr, _str);
				delete[] _str;
				_str = newstr;*/
				reserve(len + _size);
			}
			strcpy(_str + _size, str);
			_size += len;
		}
		//将有效字符串置0
		void clear() {
			_size = 0;
		}
		//resize重置有效字符个数
		//小于有效字符个数就截
		//大于补字符
		void resize(size_t num, const char ch ='\0') {
			if (num <= _size) {
				_size = num;
			}
			else {
				while (num - _size > 0) {
					push_back(ch);
				}
			}
		}
		//插入单个字符
		string& insert(size_t pos, const char ch) {
			assert(pos < _size);
			size_t size = _size;
			if (_size == _capacity) {
				size_t newcapacity = _capacity == 0 ? 2 : 2 * _capacity;
				reserve(newcapacity);
			}
			while (pos<=size) 
				{
					_str[size+1] = _str[size];
					--size;
				}
				_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(_size + len);
			}
			int size = _size;
			while ((int)pos <= size)//无符号-1是最大值,容易死循环
			{
				_str[size+len] = _str[size];
				--size;
			}
			strncpy(_str + pos, str, len);//不要复制这个字符串尾部的空格,不然会覆盖移动的字符
			_size += len;
			return *this;
		}
		//删除
		//大于等于pos到_size全删
		//小于保留余下的,并且移动
		string& erase(size_t pos,size_t len = npos) {
			assert(pos < _size);
			if (len>=_size-pos) {
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				size_t i = pos+len;
				while (i <= _size) {
					_str[pos++] = _str[i++];	
				}
				_size -= len;
			}
			return *this;
		}
		//find字符
		size_t find(const char ch, size_t pos = 0) {
			for (size_t i = pos; i < _size; ++i) {
				if (_str[i] == ch) {
					return i;
				}
			}
			return npos;
		}
		//find字符串
		size_t find(const char* str, size_t pos = 0) {
			size_t len = strlen(str);
			size_t dst = pos;
			while (dst<_size) {
				size_t src = 0;
				pos = dst;
				while (src<len&&_str[dst] == str[src]) {
					++src;
					++dst;
				}
				if (src == len) {
					return pos;
				}
				++dst;
			}
			return npos;
		}
		bool operator==(const string& s) {
			int ret = strcmp(_str, s._str);
			if (ret == 0)
				return true;
			return false;
		}
		bool operator!=(const string& s) {
			if (*this == s) {
				return false;
			}
			return true;
		}
		bool operator>(const string& s) {
			int ret = strcmp(_str, s._str);
			if (ret > 0)
				return true;
			return false;
		}
		bool operator<(const string& s) {
			int ret = strcmp(_str, s._str);
			if (ret < 0)
				return true;
			return false;
		}
		bool operator>=(const string& s) {
			if (*this < s) {
				return false;
			}
			return true;
		}
		bool operator<=(const string& s) {
			if (*this > s) {
				return false;
			}
			return true;
		}
		 const string substr(size_t pos, size_t n=npos) {
			assert(pos < _size);
			if (_size-pos<n) {
				n = _size - pos;
			}
			char* newstr = new char[n + 1];
			strncpy(newstr,_str + pos, n);
			newstr[n] = '\0';
			string s(newstr);
			delete[] newstr;
			return s;
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		const static size_t npos;
	};
	const size_t string::npos = -1;
	//重载<<
	ostream&  operator <<(ostream& _out, const string& s) {
		for (size_t i = 0; i < s.size(); ++i) {
			_out << s[i];
		}
		return _out;
	}
	//重载>>
	istream&  operator >>(istream& _in, string& s) {
		while (1) {
			char ch;
			ch = _in.get();//输入的全接收,包括空格换行
			if (ch == '\n') {
				break;
			}
			else
			{
				s += ch;
			}
		}	
		return _in;
	}
	void test_String1() {
		string s1;
		//cout << s1 << endl;
		string s2("hello");
		//cout << s2 << endl;
		//cout << s2.size() << "  " << s2.capacity() << endl;
		string s3;
		s3 = s2;
		cout << s3 << endl;
		//cin >> s1;
		//cout << s1 << "  " <
		s2 += "world";
		cout << s2 << endl;
		//迭代器访问	
		/*string::iterator it = s3.begin();
		while (it != s3.end()) {
			cout << *it << " ";
			++it;
		}
		//for
		for (auto e : s3) {
			cout << e;
		}*/
		//s2.reserve(15);
		//s2.reserve(3);
		//cout << s2 << endl;
		//cout << s2.size() << "  " << s2.capacity() << endl;
		//s3.resize(2);
		//s3.resize(10);
		//cout << s3 << endl;
		//cout << s3.size() << "  " << s3.capacity() << endl;
		//s3.push_back(' ');
		//cout << s3 << " ";
		//cout << s3.size() << "  " << s3.capacity() << endl;
		//s3.append("world!");
		//cout << s3 << " ";
		//cout << s3.size() << "  " << s3.capacity() << endl;
		//s3.insert(0,"a");
		//s3.insert(10, "abc");
		//s3.insert(5,"a");
		//s3.insert(1, 'a');
		//s3.erase(2, 8);
		//s3.erase(0);
		//s3.erase(2, 2);
		//cout << s3 << " ";
		//cout << s3.size() << "  " << s3.capacity() << endl;
		//size_t num1 =s3.find('l');
		//size_t num2 = s2.find("q",1);
		//cout << num1 << " " << num2 << endl;
		//cout << (s3>=s2)<< endl;
		//cout << s3.substr(0, 8);
	}
}


#include
int main() {
	string s1("hello");
	//cout<
	//s1.insert(1,"ac");
	//s1 += " world!";
	//s1.push_back('!');
	//s1.append("world!");
	//s1.reserve(16);
	//s1.resize(14,'a');
	//s1.clear();
	//s1.erase();
	//cout << s1.substr(2);
	//cout << s1 << endl;
	//int num = s1.find("ello",0);
	//cout << s1<<" "<
	/*string::iterator it = s1.begin();
	while (it != s1.end()) {
		cout << *it;
		++it;
		}
	cout << endl;
	string::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend()) {
		cout << *rit;
		++rit;
	}*/
	xff::test_String1();
	system("pause");
	return 0;
}


3.总结

1.迭代器是c++ STL组件之一,是通用的遍历容器的方式,讲操作和底层实现分离,我们只需要调用对应的接口,就能实现对容器的遍历,针对不同的数据结构,有规范接口的作用。
2.实现插入删除等操作时,迭代器会失效,可能会出现重新分配内存空间的情况,迭代器就失效了。
3.clear()清除有效字符,容量不变。
4.reserve(size_t n)预留空间,不改变有效字符个数,扩容作用。
5.resize(size_t n,char ch)改变有效字符个数,小于有效字符个数就只保留到n,大于当前有效字符个数就补ch到n,前面的字符不变。
6.push_back(ch)尾部插入,不可以为空,可以插空格。
7.append(str) 尾插字符串。
8.erase(pos,n)从pos开始删除n个字符,默认是最大值size_t npos=-1。
9.insert(_size,str)只能插入字符串,并且小于等于_size。
10.find(str/ch,pos)从pos位置开始查找str/ch,找到返回第一个下标,找不到返回npos,rfind反向查找。
11.c_str() 返回C格式字符串,return _str.
12.substr(pos,n)从pos截取n个字符,默认npos,返回字符串。
13.getline string类的非成员函数,获取一行字符串,空格也接收,cin会将\n和空格,作为结束的标志。
14.reverse(s.begin(),s.end()),结尾是需要逆置的字符的下一个位置。

4.心得体会

通过实现string类,我对string类的认识进一步加强,同时我也更加熟悉构造函数,析构函数等,同时对new,delete的使用更加熟练。初次学习,可能有不对的地方,希望大家指出来,共同进步。

你可能感兴趣的:(C/C++)