目的:通过模拟实现库里的string(只实现核心,或常用的功能) ,加深对其理解
在代码中已给较多注释。相信看懂已经没有什么难度。
这里便不再给出。有疑问可私信或评论
namespace my_string
{
class string
{
typedef char* iterator;
typedef const char* const_iterator;//string类并不常用迭代器,库是为了保存与其他容器的一致性
public:
//给具有const属性的使用
iterator begin()const
{
return _str;
}
iterator end()const
{
return _str + _size;
}
iterator begin()
{
return _str;
}
iterator end()
{
return _str + size();
}
//string()
// :_str("")
// , _size(0)
// , _capacity(0)
//{}
//string的初始化
//因为string是管理字符串的。
//在不考虑传string类的情况下
//初始化无非就两种情况
//1.无参 2.传一个字符串
//给一个缺省值为""的缺省参数str
//这样我们就可以对上面两种情况进行同一处理
string(const char* str = "")//加不加const 取决于是否要修改传进来的内存数据
:_str(nullptr)
, _size(strlen(str))
, _capacity(_size)
{
_str = new char[_capacity + 1]; //+1是给‘\0’准备的
strcpy(_str, str);
}
//下面处理传string类的情况,也就是同类型拷贝
string(const string& s)
:_str(nullptr)
, _size(0)
{
string tmp(s._str);//这样可以不用自己写拷贝。创建一个string ,再把他指向的内存空间交换即可
swap(tmp);
}
~string()
{
delete[]_str;
_capacity = 0;
_size = 0;
}
//返回值是引用是为了可以多次赋值
string& operator=(string s)//不传引用是为了在传参的时候直接拷贝构造一次
{
swap(s);//仿造上面拷贝构造的写法
return *this;
}
//增删查改
//实现insert 以便复用
string& insert(size_t pos, char x)//单个字符 在pos位置插入字符x,则之后的数据均往后移
{
//插入之前要先考虑容量是否足够。因此先调用reserve确保容量足够
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : 2 * _capacity);
}
//从pos开始往后的位置均往后移,为pos腾出空位
int end = size();
while (end != pos - 1)//-1是因为pos位置上的元素也要往后移动
{
_str[end+1] = _str[end];
end--;
}
_str[pos] = x;
_size++;
return *this;
}
string& insert(size_t pos, char*str)//在pos位置插入一个字符串。则之后的数据往后移动
{
//可以仿造上面的思路,往后移出足够的空间,再放入。
//也可以直接复用上面的insert.这里偷个懒选第2个
int len = strlen(str)-1;//-1是为了去掉'\0'
while (len >= 0)
{
//注意是从后往前插入
insert(pos, *(str + len));
len--;
}
return *this;
}
void push_back(const char& x)//一个字符插入 库里面有,我们可以跟着实现一个
{
//if (_size == _capacity)
//{
// reserve(_capacity == 0 ? 4 : 2 * _capacity);
//}
//_str[_size] = x;
//_size++;
//_str[_size] = '\0';
insert(size(), x);//直接复用即可 要学会摸鱼偷懒
}
string& operator+=(char c)//相当于在尾部+=一个字符
{
insert(size(), c);
}
string& operator+=(char* str)//处理上面+=一个字符字符串的情况
{
insert(size(), str);
}
//删除
string& erase(size_t pos=0, size_t len=npos)//从pos位置开始往后删除len个字符
{
assert(pos < size());
if (len == npos || pos + len >= size())//如果往后删的长度超过或等于\0,则在pos位置放个\0即可
{
_size = pos;
_str[_size] = '\0';
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
return *this;
}
void clear()
{
_str[0] = '\0';
_size = 0;
}
//查
size_t find(char ch)//找单个字符
{
for (size_t i = 0; i < size(); i++)
{
if (ch == _str[i])
{
return i;
}
}
return npos;
}
size_t find(char *s, size_t pos = 0)//从pos位置开始找跟s相同的字串
{
char *tmp = strstr(_str + pos, s);
if (tmp == nullptr)
{
return npos;
}
else
{
return tmp - _str;
}
}
//string类的比较,实现两个。其他复用
bool operator<(const string& s)
{
if (strcmp(_str, s._str)<0)
{
return true;
}
else
{
return false;
}
}
bool operator==(const string& s)
{
if (strcmp(_str, s._str) == 0)
{
return true;
}
else
{
return false;
}
}
bool operator!=(const string& s)
{
return !(*this == s);
}
bool operator>(const string& s)
{
return !((*this < s) && (*this == s));
}
bool operator<=(const string& s)
{
return !(*this>s);
}
bool operator>=(const string& s)
{
return !(*this < s);
}
char& operator[](size_t i)
{
assert(i >= 0);
return _str[i];
}
void resize(size_t n,char ch='\0')//重置容器大小
{
if (n <= _size)
{
_str[n] = '\0';
_size = n;
}
else
{
if (n > _capacity)
{
reserve(n);
}
memset(_str + _size, ch, n - _size);
_size = n;
_str[_size] = '\0';
}
}
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n+1];
for (size_t i = 0; i <= size(); i++)
{
tmp[i] = _str[i];
}
delete[]_str;
_str = tmp;
_capacity = n;
}
}
size_t size()
{
return _size;
}
size_t capacity()
{
return _capacity;
}
void swap(string& tmp)
{
std::swap(_str,tmp._str);
std::swap(_size, tmp._size);
std::swap(_capacity, tmp._capacity);
}
private:
char*_str;
size_t _size;
size_t _capacity;
static const size_t npos;
};
const size_t string::npos = -1;
}