string类的模拟实现–C++
C++中的string类是一个表示字符串的字符类,string的模拟实现也是一个考点及重点,在这里,我简单整理了一下string操作的模拟实现
模拟实现string类
class String
{
public:
//成员函数
private:
char* _str;
size_t _size;
size_t _capacity;
};
注意:_size用来表示有效字符串的长度(不包括’\0’)
_capacity表示字符串的容量大小
成员函数
- 构造函数
//构造函数
strings::String(const char* str = " ")
{
if (nullptr == str)
{
assert(false);
return;
}
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
cout << "构造:" << _str << endl;
}
- 拷贝构造
String(const String& s)
:_str(new char[s._capacity + 1])//开辟空间
, _size(s._size)
, _capacity(s._capacity)
{
strcpy(_str, s._str);//拷贝内容
cout << "拷贝:" << _str << endl;
}
注意:这里运用深拷贝,重新给_str开辟一段新的空间,再使用strcpy将形参中s._str的内容拷贝过来
- 赋值运算符重载(传的String类)
法一:传参传的为String类
String& operator=(const String& s)
{
if (this != &s)
{
delete[]_str;//释放旧的内存空间
char* pStr = new char[s._capacity + 1];//申请新的内存空间
strcpy(pStr,s._str);
_str = pStr;
_size = s._size;
_capacity = s._capacity;
}
cout << "赋值重载:" << _str << endl;
return *this;
}
注意:释放_str旧空间后,再重新申请新的空间,将传参传的String类的s._str拷贝给新的空间,再将_size,_capacity重新设置
法二:创建一个临时变量,使用了拷贝构造函数
String& operator=(const String& s)
{
if (this != &s)
{
String tmp(s);//创建一个临时变量
swap(_str, tmp._str);//使用swap函数交换
_size = tmp._size;
_capacity = tmp._capacity;
}
return *this;
}
注意:这里没有重新申请空间,但是却在函数内部利用拷贝函数重新创建了一个string类型的临时变量,再利用交换函数进行交换,而且_size,_capacity也进行重新设置
法三:
String& operator=(String& s)
{
if (this != &s)
{
//传入进来的参数是传值,相当于上面的临时变量
Swap(s);
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
void Swap(String& s)
{
swap(_str, s._str);
swap(_size, s._size);
swap(_capacity, s._capacity);
}
注意:此方法不用创建临时变量,利用了函数传参时是传值的原理,直接由编译器拷贝一份,拿来用即可
赋值运算符的重载(传的是字符串)
String& operator=(const char* str)
{
delete[]_str;//删除旧的内存空间
size_t size_str = strlen(str);//算出字符串的大小
//开辟空间
_capacity = size_str + 1;
_str = new char[_capacity];
//复制
strcpy(_str, str);
_size = _capacity - 1;
return *this;
}
- 析构函数
~String()
{
if (_str)
{
delete[]_str;
_str = nullptr;
_size = 0;
_capacity = 0;
}
}
注意:在使用new与delete是要成对使用,切记不可以混搭使用
- push_back
尾插一个字符
void PushBack(char c)
{
if (_size == _capacity)
_Reserved_(_capacity * 2);//扩容
_str[_size++] = c;//后置++
_str[_size] = '\0';
}
注意:再进行尾插操作时,一定要判断字符串的容量是否足够,不够则需进行扩容操作
尾插一个字符串
void PushBack(const char* str)
{
size_t str_size = strlen(str);
//如果容量不够,则扩容(包含'\0')
if (_size + str_size + 1 >= _capacity)
{
//扩容
_capacity += str_size;
expand(_capacity);
//拷贝
while (*str != '\0')
{
_str[_size++] = *str++;
}
_str[_size] = '\0';
}
}
//扩容(重新申请一个空间大小足够的空间,包括原来的和现在需要的空间大小)
void expand(size_t n)
{
char* tmp = new char[n];
//复制原来空间的内容
strcpy(tmp, _str);
delete[]_str;
_str = tmp;
_capacity = n;
}
- append
void Append(const char* str)
{
reserve(_size + strlen(str) + 1);
strcpy(_str + _size, str);
_size += strlen(str);
/*for (size_t i = 0; i < strlen(str); i++)
{
PushBack(str[i]);
}*/
}
注意:append函数:追加字符串str
- Insert
在指定位置插入一个字符
void Insert(size_t pos, char c)
{
if (_size < pos)
{
cout << "地址错误" << endl;
return;
}
else
{
//pos位置正常,可以插进去
if (_size + 1 >= _capacity)
{
expand(_capacity * 2);//扩容
}
_str[_size+1] = '\0';
//将pos后的位置全部向后移动一位
for (size_t i = _size; i > pos; --i)
{
_str[i] = _str[i - 1];
}
_str[pos] = c;
_size++;
}
}
注意:在插入时要先判断要插的位置是否合理,不合理便直接退出;经过判断之后,先扩容再将pos之后的位置全部向后移动一位,最后将字符放在要插的位置
在指定位置插入字符串
void Insert(size_t pos, const char* str)
{
if (_size < pos)
{
cout << "地址错误" << endl;
return;
}
size_t str_size = strlen(str);
if (str_size == 0)
{
cout << "str为空字符串" << endl;
return;
}
if (_size + str_size + 1 >= _capacity)
{
_capacity = _size + str_size + 1;
expand(_capacity);//扩容
}
int last_index = _size + str_size;
_str[last_index--] = '\0';//加'\0'
//将pos后的字符串都向后移str_size个位置
for (int i = _size - 1; i > (int)pos; --i)
{
_str[last_index--] = _str[i];
}
//插入字符
while (*str != '\0')
{
_str[pos++] = *str++;
}
_size += str_size;
}
注意:首先判断地址pos是否合理、字符串的长度是否为0;然后再扩容,并且提前加好’\0’,将pos后的字符串都向后移str_size个位置,最后插入字符
- PopBack:尾删一个字符
void PopBack()
{
if (_size == 0)
{
cout << "字符串为空" << endl;
return;
}
_size--;
_str[_size] = '\0';
}
注意:在判断字符串非空后,直接将_size减一,则完成尾删操作
- Erase:在指定位置pos之后删除一个长度为n的字符串
void Erase(size_t pos, size_t n)
{
if (pos >= _size)
{
cout << "pos的位置不合法" << endl;
return;
}
if (pos + n < _size)
{
//pos之后的字符个数大于n
size_t index_erase = pos + n;
while (index_erase != _size)
{
_str[pos++] = _str[index_erase++];
}
}
//pos之后的字符个数小于n
_str[pos] = '\0';
_size = pos;
}
- 查找字符
size_t Find(char c)
{
for (size_t i = 0; i < _size; i++)
{
if (_str[i] == c)
return i;
}
return -1;
}
- 运算符重载
+=运算符重载
String& operator+=(char c)
{
PushBack(c);
return *this;
}
[]运算符重载
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos)const
{
assert(pos < _size);
return _str[pos];
}
< > <= >= != ==的重载
bool operator>(const String& s)
{
size_t i = 0;
while (_str[i] == s._str[i] && i < _size)
{
i++;
}
if (i == _size)
{
return false;
}
}
//法一
/*bool operator==(const String& s)
{
for (int i = 0; i<_size; i++)
{
if (_str[i] != s._str[i])
{
return false;
}
}
return true;
}*/
//法二
bool operator==(const String& s)
{
size_t i = 0;
while (_str[i] == s._str[i] && i < _size)
{
i++;
}
if (i == _size && s._str[i] == '\0')
{
return true;
}
else
return false;
}
bool operator>=(const String& s)
{
if (*this > s || *this == s)
{
return true;
}
else
{
return false;
}
}
bool operator != (const String& s)
{
if (*this == s)
{
return false;
}
else
return true;
}
bool operator<=(const String& s)
{
if (!(*this > s))
{
return true;
}
return false;
}
- 容量的操作
size_t size()const
{
return _size;
}
size_t capacity()const
{
return _capacity;
}
bool empty()const
{
return 0 == _size;
}
//将有效字符的个数改成newsize,多出来的空间用c来替代
void resize(size_t newsize, char c = char())
{
if (newsize > _size)
{
if (newsize > _capacity)
{
expand(newsize);
}
memset(_str + _size, c, newsize - _size);
}
else
{
_size = newsize;
_str[newsize] = '\0';
}
}
//预留空间
void reserve(size_t newcapacity)
{
if (newcapacity > _capacity)
{
expand(newcapacity);
}
}
void print()
{
printf("%s\n", _str);
}