一.constructor构造函数
string的7种构造方法:
1.构造函数的使用![](https://img-blog.csdnimg.cn/direct/8507b1572f5840b2b484020552a090e5.png)
2.构造函数的模拟实现
使用字符串构造和无参构造的实现(注意要给'\0'多开一个字节的空间)
构造函数
string::string(const char* str )//考虑无参构造
:_str(nullptr) //构造列表,没有参数时_str=nullptr{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity+1]; // 给'\0'多开一个字节空间strcpy(_str, str);//把str的内容拷贝到_str中
}
拷贝构造的实现
拷贝构造(深拷贝)
string::string(const string& s)
{
_capacity = s._capacity;
_size = s._size;
_str = new char[s._capacity];//开空间+拷贝
strcpy(_str, s._str);
}其实拷贝构造也可以这样写:
string::string(const string& s)
{
//本来是_str自己开空间,让tmp给_str打工
string tmp(s._str);
swap(tmp);//交换tmp和*this的成员变量
}void string::swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);}
二.析构函数
构造函数是对象创建的时候自动调用的,而析构函数就是对象在销毁的时候自动调用的
//析构函数
string::~string()
{
delete[] _str;
_str = nullptr;
_size = 0;
_capacity = 0;
}
三.扩容
1.resrver
如果开的空间比n小,不做操作;如果开的空间比n大,开n+1空间并拷贝_str的内容到tmp中,再把原空间释放让_str指向tmp,_capcaity=n+1
void string::reserve(size_t n)
{
//判断一下n和capacity的大小
if (n > _capacity)
{
char* tmp = new char[n+1];
strcpy(tmp, _str);
delete[] _str; //把原空间释放
_str = tmp;
_capacity = n+1;
}
}
四.插入删除操作
1.push_back
尾插一个字符
尾插之前要检查是否capacity==size进行扩容,直接让最后的元素_str[_size] = ch,++size, _str[_size] = '\0'(尾插会把最后的'\0'覆盖,所以要将最后一位变成'\0'
void string::push_back(char ch)
{
if (_size == _capacity)
{
int newcapacity = _capacity==0?4: _capacity * 2;
//防止_str中什么都没有
//上面不需要修改_capacity
reserve(newcapacity);
}
_str[_size] = ch;
++ _size;
_str[_size] = '\0';
}
2.append
尾插一个字符串
计算一下要插入的字符串长度,如果_size(原长度) + len(str长度) + 1('\0') > _capacity就需要扩容, strcpy(_str + _size, str)将str内容拷贝过去,size+=len(strcat在_str追加str内容时不会在末尾加'\0')
void string::append(const char* str)
{
size_t len = strlen(str);
if (_size + len + 1 > _capacity)
{
reserve(_size + len + 1);
}strcpy(_str + _size, str);//strcpy会自动把'\0'拷贝过来
_size += len;
}
3.operator+=
运算符重载
重载两个版本一个可以插入字符,一个可以插入字符串
//重载两个版本
string& string::operator+= (const char ch)
{
(*this).push_back(ch);return *this;
}
string& string::operator+= (const char* str)
{
(*this).append(str);return *this;
}
4.insert
在pos插入一个字符push_back类似,不过要在插入前把pos后面的数据都向后移动一个
在pos插入一个字符串和append类似,不过要在插入前把pos后面的数据都向后移动len长度
//重载两个版本
void string::insert(size_t pos, char ch)
{
assert(pos <= _size);if (_size == _capacity)
{
int newcapacity = _capacity == 0 ? 4 : _capacity * 2;
//防止_size中什么都没有
//上面不需要修改_capacity
reserve(newcapacity);
}size_t cur = _size+1;//如果pos=0,cur-->size_t,需要将'\0'一起移动
while (pos < cur)
{
_str[cur] = _str[cur-1];
--cur;
}
_str[pos] = ch;
++_size;
}void string::insert(size_t pos,const char* str)
{
assert(pos <= _size);size_t len = strlen(str);
if (_size + len + 1 > _capacity)
{
reserve(_size + len + 1);
}size_t cur = _size + 1;//如果pos=0,cur-->size_t,需要将'\0'一起移动
while (pos < cur)
{
_str[cur+len-1] = _str[cur - 1];
--cur;
}strncpy(_str + pos, str, len);
_size += len;
}
5.erase
删除pos位置后面len个数据
void string::erase(size_t pos, size_t len)
{
assert(pos < _size);if (len==npos || pos + len >= _size)
{
_size = pos - 1;
_str[pos] = '\0';
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
}