C++:string类的模拟实现

  • string类模拟实现
    模拟实现string类
    1、首先我们需要成员变量_size记录字符串的有效字符长度,_capacity记录容量
    2、String类的6个默认成员函数
    (1)构造函数
String(const char* str = "")
	{
		if (nullptr == str)
			str = "";
		_capacity = strlen(str);
		_size = _capacity;
		_str = new char[_capacity + 1];
		strcpy(_str, str);
	}
	String(size_t n, char ch)
		:_str(new char[n + 1])
		, _capacity(n)
		, _size(n)
	{
		memset(_str, ch, _size);
		_str[_size] = '\0';
	}
	String(const char* pstr, size_t n)
	{
		size_t length = strlen(pstr);
		_size = length > n ? n : length;
		_capacity = _size;
		_str = new char[_capacity + 1];
		for (size_t i = 0; i < _size; ++i)
		{
			_str[i] = pstr[i];
		}
		_str[_size] = '\0';
	}

构造函数是创建对象,申请内存,设置_size和_capacity变量,上面实现了3个构造函数,第一个就只是利用字符串创建,第二个是创建n个字符为ch的字符串,第三个是
将字符串的n个创建。
(2)析构函数
就是出了作用域后,进行对象资源的清理
(3)拷贝构造函数

String(const String& s)//深拷贝
		:_str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
		_size = s._size;
		_capacity = s._capacity;
	}

这里的拷贝构造函数是深拷贝,给_str重新开辟重新开辟一块空间,使用strcpy函数进行拷贝。
(4)赋值运算符重载

String& operator=(const String& s)//赋值运算符重载
	{
		if (this != &s)
		{
			char* ptr = new char[strlen(s._str) + 1];
			strcpy(ptr, s._str);
			delete[]_str;
			_str = ptr;//这种方式比较好,因为上一种方法实现释放空间,后来再申请空间,可是万一后面申请空间失败,就会出错
			_size = s._size;
			_capacity = s._capacity;
		}
		return *this;
	}

这种写法是比较好的,先申请一块临时空间,利用strcpy函数进行拷贝,释放原来的空间,让它指向临时空间,改变其他变量.
3、增删改查
首先先来实现reserve函数,它是用来扩容的

void String::reserve(size_t newcapacity)
{
	if (newcapacity > capacity())
	{
		char* pStr = new char[newcapacity + 1];
		strcpy(pStr, _str);
		delete[]_str;
		_str = pStr;
		_capacity = newcapacity;
	}
}

reserve实现原理是改变容量大小,不改变有效元素个数,如果要申请的容量大于旧容量,进行扩容,反之就不扩容,如果是缩小的话,在vs下,如果>=15,不会改变容量,否则缩小容量;上面的实现原理就是先申请一个新空间,利用strcpy进行拷贝,释放原来的空间,让它指向新的空间,改变容量。
(1)增
尾插一个字符:

void String::Pushback(char ch)//尾插一个字符
{
	if (_size == _capacity)
	{
		reserve(_capacity * 2);
	}
	_str[_size++] = ch;
	_str[_size] = '\0';
}

首先判断是否需要增容,然后尾插即可。
尾插一个字符串

void String::PushBack(const char* str)
{
	size_t str_size = strlen(str);
	if (_size + str_size == _capacity)
	{
		_capacity += str_size;
		reserve(_capacity);
	}
	while (*str != '\0')
	{
		_str[_size++] = *str++;
	}
	_str[_size] = '\0';
}

先判断是否需要增容,然后将字符串的字符一个一个尾插。
头插一个字符:

void String::Pushfront(char ch)
{
	if (_size == _capacity)
	{
		reserve(_capacity * 2);
	}

	for (int i = _size; i >= 0; --i)
	{
		_str[i] = _str[i - 1];
	}
	_str[0] = ch;
	_size += 1;
	_str[_size] = '\0';
}

判断是否增容,然后从后往前将所有的字符向后移一位,然后将字符插入头部,改变有效元素个数。
头插一个字符串:

void String::Pushfront(const char* str)
{
	size_t strsize = strlen(str);//要插入的字符串的长度
	if (strsize + _size == _capacity)
	{
		_capacity = strsize + _size + 1;
		reserve(_capacity);
	}
	size_t indexPrev = _size;
	size_t indexLast = _size + strsize - 1;
	while (indexPrev)
	{
		_str[indexLast--] = _str[--indexPrev];//将当前字符串向后移strsize距离给前面腾出位置
	}
	while (*str != '\0')
	{
		_str[indexPrev++] = *str++;
	}
	_size += strsize;
	_str[_size] = '\0';
}

首先计算出要插入的字符的长度,然后判断容量是否足够,不够就增容,定义一个变量indexPre表示原字符串有效元素个数,定义一个变量indexLast表示插入后的有效元素个数,将当前字符串移出要插入的字符串的长度,然后插入。
在指定位置插入字符:

void String::insert(size_t pos, char ch)
{
	assert(pos <= _size);
	reserve(_size + 1);
	size_t end = _size;
	while (end >= pos)
	{
		_str[end + 1] = _str[end];
		end--;
	}
	_str[pos] = ch;
	_size++;
}

首先要保证插入的位置合法,然后增容,将pos后面的元素向后移一位,将指定字符插入到pos位置,改变有效元素个数。
在指定位置插入字符串:

void String::insert(size_t pos, const char* str)
{
	assert(pos <= _size);
	size_t len = strlen(str);
	size_t end = strlen(_str);
	int i = 0;
	reserve(_size + len);
	while (end >= pos)
	{
		_str[end + len] = _str[end];//pos后面的统一向后移
		--end;
	}
	while (*str)
	{
		_str[pos++] = *str++;
	}
	_size += len;
}

先判断插入位置是否合法,计算出要插入的字符串长度,扩容,将pos后的元素向后移要插入字符串的长度,插入到pos后,改变有效元素个数。
(2)删
尾删一个字符:

void String::Popback()
{
	if (_size == 0)
	{
		return;
	}
	_size--;
	_str[_size] = '\0';
}

只需要改变有效字符个数即可
头删一个字符:

void String::Popfront()
{
	for (size_t i = 0; i < _size - 1; ++i)
	{
		_str[i] = _str[i + 1];
	}
	_size--;
	_str[_size]='\0';
}

将第一个元素后的元素向前移一个位置,改变有效元素个数。
在指定位置之后删除长度为n的字符:

void String::erase(size_t pos, size_t n)//从pos开始删除长度为n的字符串
{
	assert(pos <= _size-1);
	while (_str[pos+n-1])
	{
		_str[pos-1] = _str[pos+n-1];
		pos++;
	}
	_str[pos - 1] = '\0';
	_size -= n;
}

保证pos合法,然后将n个元素之后的剩下的元素移到前面,再给末尾加上’\0’。
(3)改
[]运算符的重载:

char& String:: operator[](size_t index)
{
	assert(index < size());
	return _str[index];
}
const char& String:: operator[](size_t index)const
{
	assert(index < size());
	return _str[index];
}

返回字符串数组的字符的引用。
(4)查
查找一个字符:

size_t String::find(char ch)
{
	for (size_t i = 0; i < _size; ++i)
	{
		if (ch == _str[i])
			return i;
	}
	return -1;
}

查找一个字符串:

size_t String::find(const char* str)
{
	size_t index_str = 0;
	while (_str[index_str] != '\0')
	{
		if (_str[index_str] == *str)                         
		{//继续往后查找
			size_t find_index = index_str;
			size_t str_index = 0;
			while (1)
			{
				if (str[str_index] == '\0')//遍历完了str
				{
					return index_str;
				}
				if (_str[find_index] != str[str_index])
					break;
				find_index++;
				str_index++;
			}
		}
		index_str++;
	}
	return -1;
}

4、运算符重载
(1)+运算符重载
加一个字符(不要更改原来的对象)

String String::operator+(char ch)
{
	String strTemp(_str);
	strTemp.insert(_size, ch);
	return strTemp;
}

加一个字符串(不要更改原来的对象)

String String::operator+(const char* str)
{
	String strTemp(_str);
	strTemp.insert(_size, str);
	return strTemp;
}

(2)+=运算符重载
+=一个字符

String& String:: operator+=(char ch)
{
	insert(_size, ch);
	return *this;
}

+=一个字符串

String& String:: operator+=(const String& s)
{
	size_t leftByte = _capacity - _size;//剩了多少空间
	size_t totalByte = s.size();//拼接的字符串需要的空间
	if (totalByte>leftByte)
	{
		reserve(_size + totalByte);//申请容量
	}
	strcpy(_str + _size, s._str);//拼接到_str后
	_size += totalByte;
	return *this;
}

(3)>运算符重载

bool String::operator>(const String& s)
{
	char* pstr1 = _str;
	char* pstr2 = s._str;
	while (*pstr1 == *pstr2)
	{
		pstr1++;
		pstr2++;
	}
	if (*pstr1 > *pstr2)
		return true;
	else
	{
		return false;
	}
}

(4)>=运算符重载

bool String::operator>=(const String& s)
{
	if (*this > s || *this == s)
		return true;
	return false;
}

(5)==运算符重载

bool String::operator==(const String& s)
{
	char* pstr1 = _str;
	char* pstr2 = s._str;
	while ((*pstr1 == *pstr2) && (*pstr1 != '\0' || *pstr2 != '\0'))
	{
		pstr1++;
		pstr2++;
	}
	if (*pstr1 == *pstr2)
		return true;
	else
		return false;
}

(6)<运算符重载

bool String::operator<(const String& s)
{
	if (!(*this >= s))
		return true;
	return false;
}

(7)<=运算符重载

bool String::operator<=(const String& s)
{
	if (*this < s || *this == s)
		return true;
	return false;
}

(8)!=运算符重载

bool String::operator!=(const String& s)
{
	if (*this == s)
		return false;
	return true;
}

基本实现模拟String类的操作就是这些,其他简单的操作见源代码。
源代码(github):
https://github.com/wangbiy/C-/tree/master/test_2019_9_9_1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值