目录
string类常用的接口
string类的构造接口
string() 构造空的string类对象
string (const char* s) 用c_string来构造string类string(const string& s) 拷贝构造
c_string表示C格式的字符串,区别于string是以'\0'结尾。
void Teststring()
{
string s1;
string s2("hello world); // 用C格式字符串构造string类对象s2
string s3(s2)
}
string类对象的容量操作
size 返回字符串的有效长度
capacity 返回空间总大小
empty 检测字符串是否为空串,是返回true,否则返回false
clear 清空有效字符
reserve 为字符串预留空间
resize 将有效字符的个数改为n个,多出的空间用第二个实参填充
注意:
1、clear()只是将string中有效字符清空,不改变底层空间大小。('\0'不是有效字符)
2、resize(size_t n) 与resize(size_t n, char c)都是将字符串中的有效字符个数改为n个,第二个实参默认为0。假如n的大小大于原来的底层空间,那么就会扩容到n,复制原来的字符串,多余的空间用第二个实参填充。假如小于原来的大小,那么就截取多余的字符,但是底层的空间并不会缩小
3、reserve(size_t res_arg = 0 ):为string预留空间,不改变有效元素个数,当实参小于原底层空间大小时,也不会改变容量大小。
string类对象的访问及遍历操作
operator[] 重载了[]运算符,让string类可以和数组一样使用
begin + end 第一个字符的迭代器 + 最后一个字符的下一个位置的迭代器
rbegin + rend 最后一个字符的迭代器 + 第一个字符的前一个位置的迭代器
范围for
string类对象的修改操作
push_back 末尾加一个字符
apend 末尾加一个字符串
operator += 末尾加字符串、字符都可以
c_str 返回C格式的字符串
find + npos 从pos位置开始往后找字符c,找到了就返回该字符的位置,否则返回npos
rfind 从pos位置开始往前找字符c,找到了就返回该字符的位置,否则返回npos
substr 从pos位置截取n个字符,然后返回
string类非成员函数
operator+ 传值返回,效率低,尽量少用
operator>> 输入运算符重载
operator<< 输出运算符重载
getline cin 遇到空格就不能输入了,getline遇到回车才会停下。
模拟实现
成员变量
class string
{
private:
char* _str;
size_t _size; // 字符串中的有效字符数量('\0' 不是有效字符)
size_t _capacity;// 字符串中能够存储的有效字符数量
};
构造函数和析构函数
// 构造函数
string(const char* str = "")
{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1]; // 多开一个空间存储'\0'
strcpy(_str, str);
}
// 析构函数
~string()
{
delete[]_str;
_str = nullptr;
_size = _capacity = 0;
}
拷贝构造函数
// 拷贝构造的传统写法
string(const string& s)
:_size(strlen(s._str))
, _capacity(_size)
,_str(new char[strlen(s._str) + 1])
{
strcpy(_str, s._str);
}
//拷贝构造的现代写法
// string s1(s2);
string(const string& s)
:_str(nullptr)
{
string temp(s._str); // 让temp去调用构造函数,去构造一个string对象
swap(temp); // 直接交换,temp现在就是原来的s1,然后temp出了作用域会调用析构函数,所以_str要给一个空
}
// 调用库中的 swap 实现
void swap(const string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
size 和 capacity 接口
size_t size()
{
return _size;
}
size_t size() const // const 修饰的 string 类型使用
{
return _size;
}
size_t capacity()
{
return _capacity;
}
size_t capacity() const
{
return _capacity;
}
reserve 和 resize 接口
// 单纯只扩容
void reserve(size_t n)
{
if (n > _capacity)
{
char* temp = new char[n + 1];
strcpy(temp, _str);
delete[] _str;
_str = temp;
_capacity = n;
}
}
// 扩容 + 初始化
void resize(size_t n, char ch = '\0')
{
if (n < _size)
_size = n;
else
{
if (n > _capacity)
reserve(n);
for (size_t i = _size; i < n; i++)
_str[i] = ch;
_size = n;
}
_str[_size] = '\0';
}
insert
string& insert(size_t pos, char ch)
{
assert(pos <= _size);
if (_size == _capacity)
reserve(_capacity == 0 ? 4 : 2 * _capacity);
size_t end = _size;
while (end != pos)
{
_str[end] = _str[end - 1];
--end;
}
_str[end] = ch;
}
string& insert(size_t pos, char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity)
reserve(_size + len);
size_t end = _size + len;
while (end != pos + len)
{
_str[end] = _str[end - 1];
--end;
}
strncpy(_str + pos, str, len);
_size += len;
return *this;
}
void push_back(char ch);
{
insert(_size, ch);
}
void append(char* str)
{
insert(_size, str);
}
erase
string& erase(size_t pos, size_t len = npos)
{
assert(pos < _size);
if (len == npos || pos + len >= _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
size_t begin = pos + len;
while (begin <= _size)
{
_str[begin - len] = _str[begin];
begin++;
}
_size -= len;
}
return *this;
}
void pop_back()
{
erase(_size - 1);
}
运算重载
string& operator=(const string& s)
{
char* temp = new char[strlen(s._str) + 1];
strcpy(temp, s._str);
delete[] _str;
_str = temp;
_size = s._size;
_capacity = s._capacity;
}
char& operator[](const size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](const size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
bool operator>(const string& s)
{
return strcmp(_str, s._str) > 0;
}
bool operator==(const string& s)
{
return strcmp(_str, s._str) == 0;
}
bool operator<(const string& s)
{
return strcmp(_str, s._str) < 0;
}
bool operator>=(const string& s)
{
return *this > s || *this == s;
}
bool operator<=(const string& s)
{
return *this < s || *this == s;
}
bool operator!=(const string& s)
{
return !(*this == s);
}
输出、输入运算符重载
// 重载输出运算符
ostream& operator << (ostream& out, const string& s)
{
for (int i = 0; i < s.size(); i++)
{
cout << s[i];
}
return out;
}
istream& operator>> (istream& in, string& s)
{
while (1)
{
char ch;
//in >> ch;
ch = in.get(); // in也是一个对象
if (ch == ' ' || ch == '\n')
break;
else
s += ch;
}
return in;
}
istream& getline(istream& in, string& s)
{
while (1)
{
char ch;
//in >> ch;
ch = in.get();
if (ch == '\n')
break;
else
s += ch;
}
return in;
}
迭代器实现
string 的迭代器其实就原生指针,不需要重载迭代器的 ++ 和 *
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
const_iterator begin() const
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator end() const
{
return _str + _size;
}
void test()
{
string s;
s += '1';
s += '2';
s += '3';
s += '4';
s += '5';
s += '6';
s += '7';
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it;
++it;
}
}
整体代码实现
#pragma once
namespace yair
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
const static size_t npos = -1;
// 构造函数
string(const char* str = "")
{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1]; // 多开一个空间存储'\0'
strcpy(_str, str);
}
// 析构函数
~string()
{
delete[]_str;
_str = nullptr;
_size = _capacity = 0;
}
// 拷贝构造的传统写法
/*string(const string& s)
:_size(strlen(s._str))
, _capacity(_size)
, _str(new char[strlen(s._str) + 1])
{
strcpy(_str, s._str);
}*/
//拷贝构造的现代写法
// string s1(s2);
string(const string& s)
:_str(nullptr)
{
string temp(s._str); // 让temp去调用构造函数,去构造一个string对象
swap(temp); // 直接交换,temp现在就是原来的s1,然后temp出了作用域会调用析构函数,所以_str要给一个空
}
// 调用库中的 swap 实现
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
size_t size()
{
return _size;
}
size_t size() const // const 修饰的 string 类型使用
{
return _size;
}
size_t capacity()
{
return _capacity;
}
size_t capacity() const
{
return _capacity;
}
iterator begin()
{
return _str;
}
const_iterator begin() const
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator end() const
{
return _str + _size;
}
// 单纯只扩容
void reserve(size_t n)
{
if (n > _capacity)
{
char* temp = new char[n + 1];
strcpy(temp, _str);
delete[] _str;
_str = temp;
_capacity = n;
}
}
// 扩容 + 初始化
void resize(size_t n, char ch = '\0')
{
if (n < _size)
_size = n;
else
{
if (n > _capacity)
reserve(n);
for (size_t i = _size; i < n; i++)
_str[i] = ch;
_size = n;
}
_str[_size] = '\0';
}
string& insert(size_t pos, char ch)
{
assert(pos <= _size);
if (_size == _capacity)
reserve(_capacity == 0 ? 4 : 2 * _capacity);
size_t end = _size + 1;
while (end != pos)
{
_str[end] = _str[end - 1];
--end;
}
_str[end] = ch;
_size++;
return *this;
}
string& insert(size_t pos, char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity)
reserve(_size + len);
size_t end = _size + len;
while (end != pos + len)
{
_str[end] = _str[end - 1];
--end;
}
strncpy(_str + pos, str, len);
_size += len;
return *this;
}
void push_back(char ch)
{
insert(_size, ch);
}
void append(char* str)
{
insert(_size, str);
}
string& operator=(const string& s)
{
char* temp = new char[strlen(s._str) + 1];
strcpy(temp, s._str);
delete[] _str;
_str = temp;
_size = s._size;
_capacity = s._capacity;
}
char& operator[](const size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](const size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
bool operator>(const string& s)
{
return strcmp(_str, s._str) > 0;
}
bool operator==(const string& s)
{
return strcmp(_str, s._str) == 0;
}
bool operator<(const string& s)
{
return strcmp(_str, s._str) < 0;
}
bool operator>=(const string& s)
{
return *this > s || *this == s;
}
bool operator<=(const string& s)
{
return *this < s || *this == s;
}
bool operator!=(const string& s)
{
return !(*this == s);
}
void operator+=(char ch)
{
push_back(ch);
}
string& erase(size_t pos, size_t len = npos)
{
assert(pos < _size);
if (len == npos || pos + len >= _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
size_t begin = pos + len;
while (begin <= _size)
{
_str[begin - len] = _str[begin];
begin++;
}
_size -= len;
}
return *this;
}
void pop_back()
{
erase(_size - 1);
}
private:
char* _str;
size_t _size; // 字符串中的有效字符数量('\0' 不是有效字符)
size_t _capacity;// 字符串中能够存储的有效字符数量
};
// 重载输出运算符
ostream& operator << (ostream& out, const string& s)
{
for (int i = 0; i < s.size(); i++)
{
cout << s[i];
}
return out;
}
istream& operator>> (istream& in, string& s)
{
while (1)
{
char ch;
//in >> ch;
ch = in.get(); // in也是一个对象
if (ch == ' ' || ch == '\n')
break;
else
s += ch;
}
return in;
}
istream& getline(istream& in, string& s)
{
while (1)
{
char ch;
//in >> ch;
ch = in.get();
if (ch == '\n')
break;
else
s += ch;
}
return in;
}
void test()
{
string s;
s += '1';
s += '2';
s += '3';
s += '4';
s += '5';
s += '6';
s += '7';
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it;
++it;
}
}
}