Bootstrap

C++基础入门 String常用接口的底层模拟

常见构造接口及实现

以下为部分讲解代码,具体代码详见文末完整代码
代码实现

· 1.经典写法

class _string
{
public:
	//默认没有参数的构造
	_string()//至少开辟一个空间存档'\0',这样不会指向空
		:_data(new char[1])
	{
		_data[0] = '\0';
	}
	//全缺省构造函数
	_string(const char* ch = "")
		:_data(new char[strlen(ch)+1])//为_data开辟空间,包括最后一位'\0'
	{
		strcpy(_data, ch);
	}
	//拷贝构造(避免浅拷贝,与内存泄漏)
	_string(const _string& ch)
		:_data(new char[strlen(ch._data) + 1])//开辟空间
	{
		strcpy(_data, ch._data);
	}
	private:
	char* _data;
};

2.现代写法

//全缺省构造函数
	_string(const char* ch = "")
		:_data(new char[strlen(ch) + 1])//为_data开辟空间,包括最后一位'\0'
	{
		strcpy(_data, ch);
	}
	//拷贝构造,现代写法,使用代码复用
	_string(const _string& ch)
		:_data(nullptr)
	{
		_string temp(ch._data);//创建临时_string类对象
		swap(temp._data, _data);
	}

析构函数接口实现

~_string()
	{
		if (_data)//析构函数,判断字符串是否存在
		{
			delete[] _data;//注意用delete[],与new[]对应
			_data = nullptr;
		}
	}

赋值运算符

经典写法:

//赋值运算符重载函数
	_string& operator=(const _string& ch)
	{
		if (this != &ch)//判断是否相等
		{
			//1.释放原有空间
			delete[] _data;
			//2.申请新的空间
			_data = new char[strlen(ch._data) + 1];
			strcpy(_data, ch._data);
		}
	return *this;

	}

现代写法(重在调用构造函数)

//赋值运算符的现代写法
	//写法一
	_string& operator=(const _string& ch)
	{
		_string temp(ch._data);//会调用构造函数
		swap(temp._data,_data);	
		return *this;
	}
	//写法二
	_string& operator=(_string ch)
	{
		swap(ch._data, _data);
		return *this;

	}

begin&end迭代器

类似于指针
解引用:*iterator(获取内容)
移动位置:++iterator,–iterator

typedef char* iterator;
	const typedef char* const_iterator;
	iterator begin()
		{
		return my_data;
		}
	const_iterator begin()const
	{
		return my_data;
	}
	iterator end()
	{
		return my_data+my_size;
	}
	const_iterator end()const
	{
		return my_data + my_size;
	}

尾插函数(尾插字符、字符串)

//尾插一个字符
	void my_push_back(const char& ch)
	{
		//检查空间是否满足
		if (my_size == my_capacity)
		{
			size_t capa = my_capacity == 0 ? 15 : 2 * my_capacity;
			 reserve(capa);
		}
		my_data[my_size++] = ch;//找到最后一个字符的位置,在插入后补'/0'结尾
		my_data[my_size] = '\0';
	}
	//尾插一个字符串
	void my_append(const char* ch)
	{
	//检查容量
		size_t lenth = my_size + strlen(ch);//插入后总长度
		if (lenth > my_capacity)
		{
			reserve(lenth);
		}
		//尾插字符串
		memcpy(my_data + my_size, ch, sizeof(char)*strlen(ch));
		
		//更新参数
		my_size = lenth;
		my_data[my_size] = '\0';
	}

reserve 改变字符串空间大小

void reserve(size_t n)//申请指定大小空间,拷贝原有数据
	{
		if (n > my_capacity)
		{
			//申请空间
			char* temp = new char[n + 1];//需要多开一个空间放’'/0'
			//拷贝原有数据
			strcpy(temp, my_data);
			//释放原有空间
			delete[] my_data;
			my_data = temp;
			my_capacity = n;
		}
	}

resize 改变字符串长度

//改变字符串长度
	void resize(size_t n, const char& ch = '\0')
	{
		//判断是否大于总容量
		if (n > my_capacity)
		{
			reserve(n);
		}
		//进行填充
		if (n > my_size)
		{
			memset(my_data + my_size, ch, (n - my_size)*sizeof(char));
		}
		my_size = n;
		my_data[my_size] = '\0';
		
	}

重载运算符+=

//重载运算符+=
	_string& operator+=(const _string& ch)
	{
		my_append(ch.my_data);
		return *this;
	}

	_string& operator+=(const char* ch)
	{
		my_append(ch);
		return *this;
	}

	_string& operator+=(const char ch)
	{
		my_push_back(ch);
		return *this;
	}

重载运算符+

//重载运算符+
_string operator+(const _string& ch1, const _string& ch2)
{
	_string temp(ch1);
	temp += ch2;
	return temp;
}
_string operator+(const _string& ch1, const char* ch2)
{
	_string temp(ch1); 
	temp += ch2;
	return temp;
}
_string operator+(const _string& ch1, const char ch2)
{
	_string temp(ch1);
	temp += ch2;
	return temp;
}

插入接口

//插入接口
	//插入单个字符
	void my_insert(size_t pos, const char& ch)
	{
		//检查插入位置是否有效
		assert(pos < my_size);
		//检查容量
		if (my_size == my_capacity)
		{
			size_t cp = my_capacity == 0 ? 15 : 2 * my_capacity;
			reserve(cp);
		}
		//在pos位置及之后到size位置的元素进行移动,从后向前
		size_t _end = my_size + 1;
		while (_end>pos)
		{
			my_data[_end] = my_data[_end - 1];
			_end--;
		}
		//插入字符到pos
		my_data[pos] = ch;
		my_size++;
	}
	//插入字符串
	void my_insert(size_t pos, const char* ch)
	{
	//检查位置
		assert(pos <= my_size);
		//检查容量
		if (my_size + strlen(ch) > my_capacity)
		{
			reserve(my_size + strlen(ch));
		}
		//移动元素
		size_t _end = my_size + strlen(ch);
		while (_end > pos+strlen(ch)-1)
		{
			my_data[_end] = my_data[_end - strlen(ch)];
			_end--;
		}
		//插入元素
		memcpy(my_data + pos, ch, sizeof(char)*strlen(ch));
		//更改有效字符个数my_size
		my_size += strlen(ch);
		my_data[my_size] = '\0';
	}

删除指定长度字符函数

//删除从指定位置开始,指定长度的字符
	void my_erase(size_t pos, size_t _lenth)
	{
		//检查位置是否合理
		assert(pos < my_size);
		//移动元素,从前向后[pos+1,size]
		//判断删除的个数与剩余元素个数的关系
		if (pos + _lenth >= my_size)
		{
			my_size = pos;
			my_data[my_size] = '\0';
		}
		else
		{
			size_t _begin = pos + _lenth;//从pos开始跨越_lenth距离的位置开始往前移
			for (; _begin < my_size; ++_begin)
			{
				my_data[pos++] = my_data[_begin];
			}
			my_size -= _lenth;
		}
	}

find 相关函数

//find相关函数
	//寻找指定字符
	size_t my_find(const char& ch, size_t pos = 0)
	{
		size_t i = pos;//从指定位置开始查
		assert(i < my_size);//判断起始位置是否合理
		for (; i < my_size; i++)
		{
			if (my_data[i] == ch)
				return i;
		}
		return npos;
	}
	//寻找指定字符串
	size_t my_find(const char* ch, size_t pos = 0)
	{
		char* pi = strstr(my_data, ch);
		//若找到返回有效地址,若未找到返回NULL
		if (pi)
			return pi - my_data;
		return npos;
	}

>>与<<重载

ostream& operator<<(ostream& _out, const _string& ch)
{
	for (const auto& i : ch)
		_out << i;
	return _out;
}
istream& operator>>(istream& _in, _string& ch)
{
	char pi;
	while (pi=getchar())
	{
		if (pi == ' ' || pi == '\0' || pi == '\t')
			break;
		ch += pi;
	}
	return _in;
}

完整代码

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

class _string
{
public:
	//全缺省构造函数
	_string(const char* ch = "")		
	{
		my_size = strlen(ch);
		my_data = new char[my_size + 1];
	    my_capacity = my_size;
		strcpy(my_data,ch);
	}
	//拷贝构造函数
	_string(const _string& ch)//拷贝构造函数,采用现代写法
		:my_data(nullptr),
		my_size(0),
		my_capacity(0)
	{
		_string temp(ch.my_data);
		_swap(temp);
	}
	//交换函数
	void _swap(_string& ch)
	{
		swap(my_data, ch.my_data);
		swap(my_size, ch.my_size);
		swap(my_capacity, ch.my_capacity);
	}
	//赋值运算符
	_string& operator=(_string str) 
	{
		_swap(str);
		return *this;
	}
	//析构函数
	~_string()
	{
		if (my_data)
		{
			delete[] my_data;
			my_data = nullptr;
			my_size = my_capacity = 0;
		}
	}
	//运算符重载函数[]
	const char& operator[](size_t pi)const //不可修改
	{
		assert(pi < my_size);
		return my_data[pi];
	}
	char& operator[](size_t pi)//可以修改
	{
		assert(pi < my_size);
		return my_data[pi];
	}
	//获取字符串长度
	size_t size()const
	{
		return my_size;
	}
	//beign end 迭代器
	typedef char* iterator;
	const typedef char* const_iterator;
	iterator begin()
		{
		return my_data;
		}
	const_iterator begin()const
	{
		return my_data;
	}
	iterator end()
	{
		return my_data+my_size;
	}
	const_iterator end()const
	{
		return my_data + my_size;
	}

	//尾插一个字符
	void my_push_back(const char& ch)
	{
		//检查空间是否满足
		if (my_size == my_capacity)
		{
			size_t capa = my_capacity == 0 ? 15 : 2 * my_capacity;
			 reserve(capa);
		}
		my_data[my_size++] = ch;//找到最后一个字符的位置,在插入后补'/0'结尾
		my_data[my_size] = '\0';
	}
	//尾插一个字符串
	void my_append(const char* ch)
	{
	//检查容量
		size_t lenth = my_size + strlen(ch);//插入后总长度
		if (lenth > my_capacity)
		{
			reserve(lenth);
		}
		//尾插字符串
		memcpy(my_data + my_size, ch, sizeof(char)*strlen(ch));
		
		//更新参数
		my_size = lenth;
		my_data[my_size] = '\0';
	}
	void reserve(size_t n)//申请指定大小空间,拷贝原有数据
	{
		if (n > my_capacity)
		{
			//申请空间
			char* temp = new char[n + 1];//需要多开一个空间放’'/0'
			//拷贝原有数据
			strcpy(temp, my_data);
			//释放原有空间
			delete[] my_data;
			my_data = temp;
			my_capacity = n;
		}
	}
	//改变字符串长度
	void resize(size_t n, const char& ch = '\0')
	{
		//判断是否大于总容量
		if (n > my_capacity)
		{
			reserve(n);
		}
		//进行填充
		if (n > my_size)
		{
			memset(my_data + my_size, ch, (n - my_size)*sizeof(char));
		}
		my_size = n;
		my_data[my_size] = '\0';
		
	}
	//重载运算符+=
	_string& operator+=(const _string& ch)
	{
		my_append(ch.my_data);
		return *this;
	}

	_string& operator+=(const char* ch)
	{
		my_append(ch);
		return *this;
	}

	_string& operator+=(const char ch)
	{
		my_push_back(ch);
		return *this;
	}
	//插入接口
	//插入单个字符
	void my_insert(size_t pos, const char& ch)
	{
		//检查插入位置是否有效
		assert(pos < my_size);
		//检查容量
		if (my_size == my_capacity)
		{
			size_t cp = my_capacity == 0 ? 15 : 2 * my_capacity;
			reserve(cp);
		}
		//在pos位置及之后到size位置的元素进行移动,从后向前
		size_t _end = my_size + 1;
		while (_end>pos)
		{
			my_data[_end] = my_data[_end - 1];
			_end--;
		}
		//插入字符到pos
		my_data[pos] = ch;
		my_size++;
	}
	//插入字符串
	void my_insert(size_t pos, const char* ch)
	{
	//检查位置
		assert(pos <= my_size);
		//检查容量
		if (my_size + strlen(ch) > my_capacity)
		{
			reserve(my_size + strlen(ch));
		}
		//移动元素
		size_t _end = my_size + strlen(ch);
		while (_end > pos+strlen(ch)-1)
		{
			my_data[_end] = my_data[_end - strlen(ch)];
			_end--;
		}
		//插入元素
		memcpy(my_data + pos, ch, sizeof(char)*strlen(ch));
		//更改有效字符个数my_size
		my_size += strlen(ch);
		my_data[my_size] = '\0';
	}
	//删除从指定位置开始,指定长度的字符
	void my_erase(size_t pos, size_t _lenth)
	{
		//检查位置是否合理
		assert(pos < my_size);
		//移动元素,从前向后[pos+1,size]
		//判断删除的个数与剩余元素个数的关系
		if (pos + _lenth >= my_size)
		{
			my_size = pos;
			my_data[my_size] = '\0';
		}
		else
		{
			size_t _begin = pos + _lenth;
			for (; _begin < my_size; ++_begin)
			{
				my_data[pos++] = my_data[_begin];
			}
			my_size -= _lenth;
		}
	}

	//find相关函数
	//寻找指定字符
	size_t my_find(const char& ch, size_t pos = 0)
	{
		size_t i = pos;//从指定位置开始查
		assert(i < my_size);//判断起始位置是否合理
		for (; i < my_size; i++)
		{
			if (my_data[i] == ch)
				return i;
		}
		return npos;
	}
	//寻找指定字符串
	size_t my_find(const char* ch, size_t pos = 0)
	{
		char* pi = strstr(my_data, ch);
		//若找到返回有效地址,若未找到返回NULL
		if (pi)
			return pi - my_data;
		return npos;
	}
	void my_out()
	{
		cout << my_data << endl;
		cout << my_size << endl;
	}
private:
	char* my_data;
	//size: 有效字符的个数
	size_t my_size;
	//字符串的容量
	size_t my_capacity;
	static const size_t npos;
};
const size_t _string::npos = -1;
//重载运算符+
_string operator+(const _string& ch1, const _string& ch2)
{
	_string temp(ch1);
	temp += ch2;
	return temp;
}
_string operator+(const _string& ch1, const char* ch2)
{
	_string temp(ch1); 
	temp += ch2;
	return temp;
}
_string operator+(const _string& ch1, const char ch2)
{
	_string temp(ch1);
	temp += ch2;
	return temp;
}
ostream& operator<<(ostream& _out, const _string& ch)
{
	for (const auto& i : ch)
		_out << i;
	return _out;
}
istream& operator>>(istream& _in, _string& ch)
{
	char pi;
	while (pi=getchar())
	{
		if (pi == ' ' || pi == '\0' || pi == '\t')
			break;
		ch += pi;
	}
	return _in;
}

欢迎批评指正

;