STL学习-自模拟实现String类

文章详细介绍了如何使用C++模拟实现一个简单的string类,包括构造函数、拷贝构造函数、赋值运算符重载、容量管理、访问和遍历、修改操作以及流插入和提取等关键功能。同时对比了传统和现代写法的差异,如拷贝构造和赋值运算符的实现策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

string模拟实现

公有及私有成员预览

#pragma once

using namespace std;
namespace carl
{
	class string
	{
	public:
		
		//迭代器相关
		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin();
		iterator end();
		const iterator begin()const;
		const iterator end()const;

		//默认成员
		string(const char* str = "");
		string(const string& s);
		~string();
		string& operator=(const string& s);

		//容量相关
		size_t size()const;
		size_t capacity()const;
		void reserve(size_t n);
		void resize(size_t n, char ch='\0');
		void clear();

		//访问及遍历相关
		const char& operator[](size_t pos) const;
		char& operator[](size_t pos);

		//修改相关
		void push_back(char ch);
		const char* c_str();

		void append(const char* str);
		void append(const string& s);
		
		string& operator+=(const char* str);
		string& operator+=(const char ch);
		string& operator+=(const string& s);
		
		string& insert(size_t pos, char ch);
		string& insert(size_t pos, const char* str);
		
		void erase(size_t pos,size_t len=npos);
		
		size_t find(char ch, size_t pos = 0)const;
		size_t find(const char* str, size_t pos = 0)const;

		string substr(size_t pos, size_t len = npos)const;
		
		void swap(string& temp);

		//重载运算符相关
		bool operator>(string& s)const;
		bool operator==(string& s)const;
		bool operator>=(string& s)const;
		bool operator<(string& s)const;
		bool operator<=(string& s)const;
		bool operator!=(string& s)const;
		
	private:
		size_t _size;
		size_t _capacity;
		char* _str;
	public:
        const static size_t npos=-1 ;
	};
	//流提取和流插入
	ostream& operator<<(ostream& out, const string& s);
	istream& operator>>(istream& in, string& s);
}

默认成员函数

我们只自模拟实现四个默认成员函数:构造,拷贝构造,析构,赋值运算符重载

其中:拷贝构造,赋值运算符重载,我们有两种写法:传统写法和现代写法。

现代写法相对于传统写法来说效率较高且较简洁,而传统写法可读性较高。

我们首先给出这四个默认成员函数的传统写法(现代写法需要依赖复用构造函数)

传统写法

构造函数

//默认成员(传统)
		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity+1] ;
			
			strcpy(_str, str);
		}

析构函数

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

拷贝构造

string(const string& s)
			:_str(new char[s._capacity + 1])
			,_size(s._size)
			,_capacity(s._capacity)
		{
			strcpy(_str, s._str);
		}

赋值运算符重载

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

				delete[] _str;

				_str = temp;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}

现代写法

拷贝构造

string(const string& s)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			string tmp(s._str);
			swap(tmp);
		}

赋值运算符重载

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

区别

简析传统写法和现代写法的区别:

传统拷贝构造思路

image-20230531124714896

现代拷贝构造思路:复用了构造函数,利用了swap函数

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

image-20230531131645258

传统赋值

image-20230531132648868

现代赋值:调用拷贝构造函数以实参为模板拷贝形参,再利用swap函数将目标主体与形参交换,出了函数作用域后形参会自动销毁

容量相关

直接给出代码自模拟实现代码:

size_t size()const
size_t capacity()const
void reserve(size_t n)
void resize(size_t n, char ch = ‘\0’)
void clear()
//容量相关
		
size_t size()const
		{
			return _size;
		}
		
size_t capacity()const
		{
			return _capacity;
		}
		
	
void reserve(size_t n)
		{
			if(n>_capacity)
			{
				char* temp = new char[n+1];
				strcpy(temp, _str);
				delete[] _str;
				_str = temp;
				_capacity = n;
			}
  	  //n<capacity什么都不用做
		}

		
void resize(size_t n, char ch = '\0')
		{
			if (n > _size)
			{
				reserve(n);
				for (size_t i = _size;i < n;i++)
				{
					_str[i] = ch;
				}
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				_str[n] = '\0';
				_size = n;
			}
		}

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

访问及遍历相关

const char& operator[](size_t pos) const;
char& operator[](size_t pos);
//访问及遍历相关
		const char& operator[](size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

修改相关

void push_back(char ch)

const char c_str()const*

void append(const char str);*

void append(const string& s);

string& operator+=(const char str);*

string& operator+=(const char ch);

string& operator+=(const string& s);

string& insert(size_t pos, char ch);

string& insert(size_t pos, const char str);*

void erase(size_t pos,size_t len=npos);

size_t find(char ch, size_t pos = 0)const;

size_t find(const char str, size_t pos = 0)const;*

string substr(size_t pos, size_t len = npos)const;

//修改相关
//尾插
void push_back(char ch)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			}
			_str[_size++] = ch;
			_str[_size] = '\0';
		}
//返回c语言风格字符串
const char* c_str()const
		{
			return _str;
		}

//追加一个字符串	
void append(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			strcpy(_str + _size, str);
			_size = _size + len;
		}
//追加一个string类型
void append(const string& s)
		{
			append(s._str);
		}
		
//+=字符串		
string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
//+=字符	
string& operator+=(const char ch)
		{
			push_back(ch);
			return *this;
		}
//+=string类型	
string& operator+=(const string& s)
		{
			append(s._str);
			return *this;
		}
		
//在pos位置插入一个字符	
string& insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			}
			size_t end = _size+1;
			while (end > pos)
			{
				_str[end] = _str[end-- - 1];
			}
			_str[pos] = ch;
			_size++;
			_str[_size+1]='\0';
			return *this;
		}
//在pos位置插入一个字符串	
string& insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			size_t end = _size + len;
			while (end > pos + len)
			{
				_str[end] = _str[end-- - 3];

			}
			strncpy(_str + pos, str, len);
			_size += len;
			_str[_size + 1] = '\0';
			return *this;
		}

//删除pos位置开始长度为len的字符串	
void erase(size_t pos, size_t len = npos)
		{
			assert(pos <= _size);
			if (len == npos || pos + len > _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
		}
		
//在pos位置开始找一个字符并返回其下标
size_t find(char ch, size_t pos = 0)const
		{
			assert(pos <= _size);
			for (size_t i = pos;i < _size;i++)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}
//在pos位置开始找到一个字符串并返回该字符串开始的下标		
size_t find(const char* str, size_t pos = 0)const
		{
			assert(str);
			assert(pos <= _size);
			const char* ptr = strstr(_str + pos, str);
			if (ptr == nullptr)
			{
				return npos;

			}
			else return ptr - _str;
		}

//截取pos位置之后的长度为n的字符串	
string substr(size_t pos, size_t len = npos)const
		{
			assert(pos < _size);
			size_t RLen = len;
			if (len == npos || pos + len > _size)
			{
				RLen = _size - pos;
			}
			string tmp;
			for (size_t i = pos;i < RLen;i++)
			{
				tmp += _str[i];
			}
			return tmp;
		}

关于insert给出动图演示:

insert2insert

重载运算符相关

实现两个,其他复用

//重载运算符相关
		bool operator>(string& s)const
		{
			return strcmp(_str, s._str)>0;
		}
		bool operator==(string& s)const
		{
			return strcmp(_str, s._str) == 0;
		}
		bool operator>=(string& s)const
		{
			return *this > s || *this == s;
		}
		bool operator<(string& s)const
		{
			return !(*this >= s);
		}
		bool operator<=(string& s)const
		{
			return!(*this > s);
		}
		bool operator!=(string& s)const
		{
			return !(*this == s);
		}

流提取和流插入重载

//流提取
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)
	{
		s.clear();
		char ch;
		ch = in.get();
   //数组出了作用域会销毁,因此先放进数组里,再+=到string中,这样方便且能避免过长而扩容太多的情况
		const size_t N = 32;
		char buff[N];
		size_t i= 0;
		while (ch != ' ' || ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}
		buff[i] = '\0';
		s += buff;
		return in;
	}
//getline
istream& getline(istream& in,string& s)
	{
		s.clear();
		char ch = in.get();
		while (ch != '\n')
		{
			s += ch;
			ch = in.get();
		}
		return in;
	}

迭代器相关

iterator begin()
		{
			return _str;
		}
	
iterator end()
		{
			return _str + _size;
		}
	
const iterator begin()const
		{
			return _str;
		}
	
const iterator end()const
		{
			return _str + _size;
		}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值