string 类的模拟实现
string类的学习目的
在字符串OJ中,为了简单、方便、快捷,基本都使用string类。
string类的一些特性
-
string是表示字符串的字符串类
-
该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
-
string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>
string;basic_string是一个模板类,它接受三个参数:char表示字符类型,char_traits表示字符特性,allocator表示内存分配器。通过这三个参数的组合,我们可以实例化出不同类型的字符串类。 这句代码总而言之就是将basic_string<char, char_traits, allocator>定义为string类型的别名,这样在后续的代码中,我们就可以直接使用string来表示这个特定的字符串类型,而无需再写出完整的模板参数列表。
-
不能操作多字节或者变长字符的序列。
在使用string类时,必须包含#include头文件以及using namespace std;
string类的常用接口
1.string类对象的常见构造,模拟实现
class string
{
public:
//构造函数
//为了使得private中的char* _str能够不使用const,写出构造函数,在初始化中
//如果我们使用直接赋值,如主函数中为string s1; 构造函数中是_str = str;那么就
//会出现权限放大的现象,即将const变量赋值给普通变量,这是不允许的,故我们在初始
//化列表中进行开空间,以及拷贝字符串,避免了直接赋值权限放大的情况
string(const char* str = "")
: _size(strlen(str))
{
_capacity = _size== 0 ? 3 : _size;
_str = new char[_capacity + 1];
strcpy_s(_str, _capacity + 1, str);
}
//拷贝构造函数
string(const string& s)
:_size(s._size)
, _capacity(s._capacity)
{
_str = new char[s._capacity + 1];
strcpy_s(_str, s._capacity + 1, s._str);
}
private:
char* _str;
size_t _size;
size_t _capacity;
};
2. string类对象的容量操作,模拟实现
//对字符串空间进行扩容操作
void reserve(size_t n)
{
//防止缩容
if(n > _capacity)
{
char* tmp = new char[n + 1];//开辟新空间
strcpy_s(tmp, n + 1, _str);//将旧空间的字符串赋值到新空间
delete[] _str;//删除旧空间内容,释放旧空间
_str = tmp;//将指向旧空间的指针重新指向新的空间
_capacity = n;//将新的空间的大小给_capacity变量
}
}
3. string类对象的访问及遍历操作,模拟实现
//对字符串进行访问对应位置数据
//有以下几种方法
1.operator[]运算符重载:返回pos位置的字符,const string类对象调用
//非const变量调用
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
//const变量调用
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
2.iterator迭代器访问对应位置字符:begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭
代器
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
iterator begin() const
{
return _str;
}
iterator end() const
{
return _str + _size;
}
//在主函数中可以这样来遍历字符串
int main()
{
string s1("hello world");
string::iterator it = s1.begin();
while(it != s1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
}
3.范围for
//底层实现就是iterator迭代器
//接着上面的main函数,可以这样使用
for(auto ch : s1)
{
cout << ch << " ";
}
cout << endl;
4.string类对象的修改操作,模拟实现
//在字符串后尾插字符c
void push_back(char ch)
{
if(_size + 1 > _capacity)//扩容操作
{
reserve(_capacity * 2);
}
_str[_size] = ch;
_size++;
_str[_size] = '\0';
}
//在字符串后追加一个字符串
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
strcpy_s(_str + _size, _capacity - _size, str);
_size += len;
}
//运算符重载+=
//后面加字符
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
//后面加字符串
string& operator+=(const char* str)
{
append(str);
return *this;
}
5.string类对象的比较操作,模拟实现
//不改变的变量最好加上const
bool operator>(const string&s) const
{
return strcmp(_str, s._str)>0;
}
bool operator==(const string& s) const
{
return strcmp(_str, s._str) == 0;
}
//复用操作
bool operator>=(const string& s) const
{
return *this > s || *this == s;
}
bool operator<(const string& s) const
{
return !(*this >= s);
}
bool operator<=(const string& s) const
{
return !(*this > s);
}
bool operator!=(const string& s) const
{
return !(*this == s);
}