今天复习了string类,做笔记方便日后复习
首先先看一下我们要实现的string类的成员变量和成员函数:
class string
{
public:
string(char* str = "");//构造函数
//string(const string& s); //拷贝构造传统写法
string(const string& s); //拷贝构造现代写法
~string();//析构函数
size_t size() const;//返回有效字符个数
size_t capacity();//返回容量
char& operator[](size_t i);//实现和数组一样通过下标访问的功能
const char& operator[](size_t i) const;//实现和数组一样通过下标访问的功能(const对象也可访问)
const char* c_str() const;//返回c形式字符串(const对象也可访问)
char* c_str();//返回c形式字符串
string& operator=(const string& s);//重载赋值运算符
typedef char* iterator;//返回迭代器,通过迭代器访问数据
iterator begin();//返回头迭代器
iterator end();//返回尾迭代器
void reverse(size_t newcapacity);//扩容函数
void push_back(char ch);//尾插字符
void append(const char* str);//尾插字符串
string& insert(size_t pos, char ch);//任意位置插入字符
string& insert(size_t pos, const char* str);//任意位置插入字符串
string& operator+=(char ch);//重载+=运算符 和push_back功能相同
string& operator+=(const char* str);//重载+=运算符 和append功能相同
void erase(size_t pos, size_t len = npos);//清除从pos位置开始的len个字符
private:
char* _str;//存储字符串
size_t _size;//有效字符个数
size_t _capacity;//字符串容量
static size_t npos;//用它作为一些函数的默认参数,static修饰,在类外初始化
};
图解_str、_size、_capacity三个成员变量:
看完这个类的大体结构,我们开始对其实现
构造函数(一般要实现无参和有参两个构造函数,为了简便我们通过传默认参数用一个构造函数实现有参构造和无参构造两个功能):
string(char* str = "")
:_str(new char[strlen(str) + 1])//因为堆上的空间方便增容,因此我们在堆上开辟空间
{
strcpy(_str, str);//将str拷贝到对象的_str中
}
析构函数:
~string()
{
delete[] _str;//我们在堆上为_str开辟了空间,为防止内存泄漏,我们要将其释放
_str = nullptr;//防止野指针,将其置空
}
拷贝构造函数(传统写法):
string(const string& s)
:_str(new char[strlen(s._str) + 1])//防止浅拷贝,首先为构造对象在堆上开辟空间
{
strcpy(_str, s._str);
}
拷贝构造函数(现代写法):
string(const string& s) //现代写法
:_str(nullptr)
{
string tmp(s._str);//虽然tmp是局部变量函数结束会销毁,但它的_str是在堆上开辟的对象,需要我们手动释放,this的_str和s的_str交换不用担心手动释放的问题,因为tmp销毁会去释放this的_str
swap(_str, tmp._str);
}
返回有效字符个数(不想让别人改变的我们用const修饰符):
size_t size() const //使用const修饰,const和非const的对象都可以访问
{
return _size;
}
返回字符串容量:
size_t capacity()
{
return _capacity;
}
重载[]运算符:
char& operator[](size_t i)
{
assert(i < _size);
return _str[i];
}
const char& operator[](size_t i) const
{
assert(i < _size);
return _str[i];
}
返回c形式字符串:
const char* c_str() const
{
return _str;
}
char* c_str()
{
return _str;
}
重载赋值运算符(传统写法)
string& operator=(const string& s)
{
if (this != &s)
{
char* tmp = new char[s._capacity + 1];
delete[] _str;
_str = tmp;
_capacity = s._capacity;
_size = s._size;
}
return *this;
}
重载赋值运算符(现代写法)
string& operator=(const string& s)
{
if (this != &s)
{
string tmp(s._str);
swap(_str, tmp._str);
}
return *this;
}
返回begin迭代器:
iterator begin()
{
return _str;
}
图示:
返回end迭代器
iterator end()
{
return _str + _size;
}
字符串扩容函数(当我们使用pushback或者append时,有时会出现空间不足的问题,如果强行访问就会出现指针越界的情况,因此这时要对字符串进行扩容)
void reverse(size_t newcapacity)
{
if (newcapacity > _capacity)//防止误调用,当newcapacity>_capacity时执行下面的函数
{
char* tmp = new char[newcapacity + 1];//+1是因为'\0'不是有效字符,但是字符串末尾要存'\0'因此多开辟一个空间
strcpy(tmp, _str);
delete[] _str;//释放原来的空间
_str = tmp;//_str指向新开辟的空间
_capacity = newcapacity;
}
}
尾插字符:
void push_back(char ch)
{
if (_size == _capacity)//判断字符串容量是否足够
{
size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;//如果是空string我们要为其开辟空间,这里默认为2,如果不是空string扩大为原来的2倍
reverse(newcapacity);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';//尾部插入会覆盖原来的'\0',因此最后面要插入一个'\0'
}
尾插字符串:
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
size_t newcapacity = _capacity + len;
reverse(newcapacity);
}
strcpy(_str + _size, str);
_size += strlen(str);
}
图示:
任意位置差入字符:
string& insert(size_t pos, char ch)
{
assert(pos < _size);
if (_size == _capacity)
{
size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;
reverse(newcapacity);
}
int end = _size;
while (end >= pos)
{
_str[end + 1] = _str[end];
--end;
}
_str[pos] = ch;
++_size;
return *this;
}
图示:
任意位置插入字符串:
string& insert(size_t pos, const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
size_t newcapacity = _size + len;
reverse(newcapacity);
}
int end = _size;
while (end >= pos)
{
_str[end + len] = _str[end];
end--;
}
for (int i = 0; i < len; i++)
{
_str[pos + i] = str[i];
}
_size += len;
return *this;
}
重载+=一个字符:
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
重载+=一个字符串:
string& operator+=(const char* str)
{
append(str);
return *this;
}
清除从任一位置开始的len个字符:
void erase(size_t pos, size_t len = npos)
{
if (len >= _size - pos)
{
_str[pos] = '\0';
_size = pos;
}
else
{
size_t i = pos + len;
while (i <= _size)
{
_str[i - len] = _str[i];
++i;
}
_size -= len;
}
}
图示:
水平有限,希望大家结合图示理解。