C++STL-sting类的模拟实现
默认成员函数
构造函数
string(const char* str = "")
{_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];//开辟容量加1空间,用于存放"\0"strcpy(_str, str);//将空字符串拷贝到新开的空间中
}
拷贝构造函数
要注意写成深拷贝
传统写法
开辟一块能容纳原字符串的空间,在把原字符串拷贝过去,成员变量也赋值过去即可
string(const string& s):_str(new char[s._capacity + 1]),_size(0),_capacity(0)
{strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;
}
现代写法
构造出的tmp对象与要被拷贝的对象数据交换即可
string(const string& s):_str(nullptr), _size(0), _capacity(0)
{string tmp(s._str);//调用构造函数构造tmpswap(tmp);
}
赋值运算符重载函数
传统写法
string& operator=(const string& s)
{if (this != &s)//防止自己给自己赋值{delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;//返回左值,支持连续赋值
}
现代写法1
string& operator=(string s)//编译器接受右值自动调用拷贝构造
{swap(s);return *this;
}
现代写法2
多了一个防止自己给自己赋值
string& operator=(const string& s)
{if (this != &s){string tmp(s);swap(tmp);}return *this;}
析构函数
~string()
{delete[] _str;//释放指向的空间_str = nullptr;_size = 0;_capacity = 0;
}
迭代器相关函数
起别名
typedef char* iterator;
typedef const char* const_iterator;
begin和end
iterator begin()
{return _str;//返回字符第一个地址
}const_iterator begin()const
{return _str;
}
iterator end()
{return _str + _size;//返回最后一个字符后一个字符的地址
}const_iterator end()const
{return _str + _size;
}
容量和大小相关函数
用成员函数来获取成员变量
size
size_t size()const
{return _size;//返回字符串有效长度(不包括"/0")
}
capacity
size_t capacity()const
{return _capacity;//返回字符串容量
}
reserve和resize
reserve规则:
1.n>capacity,capacity扩大到n倍;
2.n<capacity,不操作
void reserve(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1];//多开一个空间存放"/0"strncpy(tmp, _str, _size + 1);//将原字符串拷贝过去,包括"\0"delete[] _str;//释放原来空间_str = tmp;//新开辟的空间改名_capacity = n;//capacity更新为n}
}
resize规则:
1.n>size,将size扩大到n
2.n<size,将size减小到n
void resize(size_t n,char ch='\0'){if (n <= _size){_size = n;_str[_size] = '\0';}else{if (n > _capacity){reserve(n);}for (size_t i = _size; i < n; i++)//将size扩大到n,扩大的字符为ch{_str[i] = ch;}_size = n;_str[_size] = '\0';}}
empty
strcmp函数用来比较两个字符串大小,相等返回0
bool empty()
{return strcmp(_str, "") == 0;
}
修改字符串相关函数
push_back
尾插字符
void push_back(char ch)//追加字符
{if (_size == _capacity)//判断是否需要扩容{reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_str[_size+1] = '\0';_size++;//字符串大小加1
}
或者复用insert函数
void push_back(char ch)
{insert(_size, ch);}
append
追加字符串
void append(const char* str)
{size_t len = _size + strlen(str);if (len > _capacity)//判断是否需要扩容{reserve(len);}strcpy(_str + _size, str);//尾插字符串_size = len;//更新_size
}
也能复用insert函数
void append(const char* str)
{insert(_size,str);
}
operator+=
实现字符串与字符之间的尾插调用push_back即可
string& operator+=(char ch)
{push_back(ch);return *this;
}
实现字符串与字符串之间的尾插调用append即可
string& operator+=(const char*str)
{append(str);return *this;
}
insert
在pos位置插入字符
string& insert(size_t pos, char ch)
{assert(pos <= _size);//检查下标是否合法性if (_size == _capacity)//判断是否要扩容{reserve(_capacity == 0 ? 4 : _capacity * 2);}char* end = _str + _size;while (end >= _str + pos)//pos位置之后向后移动一位{*(end + 1) = *end;}_str[pos] = ch;//在pos位置放置字符_size++;//更新sizereturn *this;
}
在pos位置插入字符串
erase
string& erase(size_t pos, size_t len = npos)
{assert(pos < _size);size_t n = _size - pos;if (len >= n)//pos位置之后都要被删掉{_size = pos;_str[_size] = '\0';}else{strcpy(_str + pos, _str + pos + len);//需要保留的字符往前覆盖_size -= len;}return *this;//支持链式调用
}
clear
void clear(){_size = 0;_str[_size] = '\0';}
swap
void swap(string& s)
{::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);
}
c_str
返回c类型的字符串
const char* c_str()const
{return _str;
}
访问字符串相关函数
operator[]
char& operator[](size_t i)//可读可写
{assert(i < _size);return _str[i];}const char& operator[](size_t i)const//只读
{assert(i < _size);return _str[i];
}
find
正向查找第一个字符
size_t find(char ch, size_t pos = 0)
{assert(pos < _size);for (size_t i = pos;i<_size; i++){if (ch == _str[i]){return i;}}return npos;
}
正向查找第一个字符串
size_t find(const char* str, size_t pos = 0)
{assert(pos < _size);const char* ret = strstr(_str + pos, str);if (ret){return ret - _str;}else{return npos;}
}
refind(调用find函数实现)
反向查找第一个匹配到的字符
size_t rfind(char ch, size_t pos = npos)
{string tmp(*this);//拷贝构造对象tmpreverse(tmp.begin(), tmp.end());if (pos >= _size){pos = _size - 1;}pos = _size - 1 - pos;//镜像对称possize_t ret =tmp.find(ch, pos);if (ret != npos)return _size - 1 - ret;elsereturn npos;
}
反向查找第一个匹配到的字符串
size_t rfind(const char* str, size_t pos = npos)
{string tmp(*this);//逆置字符串reverse(tmp.begin(), tmp.end());//逆置要查找的字符size_t len = strlen(str);char* arr = new char[len + 1];strcpy(arr, str);size_t left = 0,right = len - 1;while (left < right){::swap(arr[left], arr[right]);left++;right--;}if (pos >=_size){pos = _size - 1;}pos = _size - 1 - pos;size_t ret = tmp.find(arr, pos);delete[] arr;if (ret != npos)return _size - len - ret;elsereturn npos;}
关系运算符重载函数
//>运算符重载
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);}
>>和<<运算符重载以及getline函数
istream& operator>>(istream& in, string& s)
{s.clear();//清空字符串char ch = in.get();while (ch != ' ' && ch != '\n'){s += ch;追加字符ch = in.get();}return in;//支持连续输入
}ostream& operator<<(ostream& out, const string& s)
{for (auto e : s){cout << e;}return out;
}
getline
读取一行含有空格的字符串
istream& getline(istream& in, string& s)
{s.clear();char ch = in.get();while (ch != '\n'){s += ch;ch = in.get();}return in;
}