cpp
复制代码
namespace simulate_string
{
class string
{
private:
char* _str;
size_t _size;
size_t _capacity;
const static int npos = -1;//类型说明+作用域变量;
public:
typedef char* iterator;
typedef const char* const_iterator;
//迭代器相当于直接调用该类型的指针
iterator begin()//指向首元素地址
{
return _str;
}
const_iterator begin() const
{
return _str;
}
iterator end()//指向末尾元素的下一个地址,在string类中该地址存放的是'\0'
{
return _str+_size;
}
const_iterator end()const
{
return _str + _size;
}
//构造函数
string(const char* str="")
:_size(strlen(str))
{
_capacity = _size;//防止_size和_capacity声明顺序与初始化列表顺序相反;
//开空间(_capacity是有效容量不包括'\0')
_str = new char[_capacity+1];
strcpy(_str,str);
}
//拷贝构造
string(const string& s)
:_size(s._size)
{
_capacity = s._capacity;
_str = new char[_capacity + 1];//多一个空间存放'\0'
strcpy(_str,s._str);//会拷贝'\0';
std::cout << "string(const string& s)" << std::endl;
}
//移动拷贝构造(移动语义)
string(string&& s)//这里右值引用为什么不需要加const?因为要对右值进行资源转移。
{
swap(s);
std::cout << "string(string&& s)" << std::endl;
}
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
~string()
{
delete[] _str;
_str = nullptr;
_capacity = _size = 0;
}
size_t size() const
{
return _size;
}
char& operator[](size_t pos)
{
assert(pos<_size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
const char* c_str()
{
return _str;
}
//赋值运算符重载
string& operator=(const string& s)
{
if (this != &s)
{
char* tmp = new char[s._capacity + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
// 不修改成员变量数据的函数,最好都加上const
//strcmp会返回0,-1,1;分别代表相等,小于,大于;
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);
}
void push_back(char& ch)
{
insert(_size,ch);
}
void append(const char* str)
{
insert(_size,str);
}
//如果出现s1+=s1的情况,阁下该如何应对?
string& operator+=(const string& s)
{
if (this!= &s)
{
append(s._str);
}
else
{
//创建临时对象;
string news(s);
append(news._str);
}
return *this;
}
string& operator+=(char& ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
void reserve(size_t n)//不能缩容
{
if (n > _capacity)//需要的空间大于当前容量才进行扩容!
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;//有效容量不包括\0;
}
}
void resize(size_t n,char ch='\0')//开空间加初始化
{
if (n <= _size)
{
_size = n;
_str[_size] = '\0';
}
else
{
if (n>_capacity)
{
reserve(n);
}
int i = _size;
while (i < n)
{
_str[i] = ch;//初始化为传递的字符,没有就使用默认缺省;
++i;
}
_size = n;
_str[_size] = '\0';
}
}
string& insert(size_t pos,char ch)
{
assert(pos<=_size);
if (_size + 1 > _capacity)//需要扩容
{
reserve(_capacity * 2);
}
size_t end = _size+1;
while (end>pos)//当pos为0这种情况时,无符号整数0再减1是无符号整数的最大值而不是-1,所以当end从0再减1时,会继续循环,访问_str[max],程序会崩;
{
//_str[end+1] = _str[end];不可以程序会崩;
_str[end] = _str[end-1];
--end;
}
_str[pos] = ch;
++_size;
return *this;
}
string& insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);//计算要插入字符的长度;
if (_size + len > _capacity)
{
reserve(len + _size);//需要开辟的有效空间,不包括'\0'
}
size_t end =_size;
while (end>pos)//当end最小为1;
{
_str[end+len-1]=_str[end-1];
--end;
}
strncpy(_str+pos,str,len);//strcpy会把默认字符串的'\0'也加在后面,会覆盖原字符串的后面第一个字符;
_size += len;
_str[_size] = '\0';
return *this;
}
string& erase(size_t pos=0,size_t len=npos)//如果不说明删除多少个,默认从当前位置删到完;
{
assert(pos<_size);
if (len==npos||pos+len>=_size)//如果前面不判断len==npos,后面pos+len会溢出,size_t无符号正整数最大就是-1的补码,因为是无符号;
{
_size = pos;
_str[_size] = '\0';
}
else
{
//连'\0'都拷贝,把_str+pos+len以后的所有字符都拷贝过来;
strcpy(_str+pos,_str+pos+len);
_size -= len;
}
return *this;
}
//返回一个字符在_str中第一次出现的位置;
size_t find(char ch,size_t pos=0)
{
assert(pos<_size);
int i = 0;
while (i<_size)
{
if (_str[i]==ch)
{
return i;
}
++i;
}
return npos;
}
//返回一个字符在_str中最后一次出现的位置;
//实质是在_str中从后往前找与ch相等的下标索引;
size_t rfind(char ch,size_t pos=npos)//size_t类型的pos被赋予size_t类型的npos=-1,则npos等于max int;
{
assert(pos>=0);
if (pos == npos||pos>=_size)
pos = _size-1;
int i =pos;
while (i>=0)
{
if (_str[i]==ch)
{
return i;
}
--i;
}
return npos;
}
//按顺序找_str中在str中第一次出现的位置,返回一个指针,指向这个字符;
size_t find(const char* str,size_t pos=0)
{
assert(pos<_size);
//解释strstr();实际上就是找字符串str在_str中第一次出现的位置;
//Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
char* p = strstr(_str+pos,str);
//库里面的,按顺序找字符串2在字符串1中第一次出现的位置;
if (p==nullptr)
{
return npos;
}
else
{
return p-_str;
}
}
};
//************* 类外 ***************
//流插入(写到类外保证cout<<s的格式),不用友元函数也可以访问s对象的每一个字符
std::ostream& operator<<(std::ostream& out,const string& s)
{
for (int i=0;i<s.size();++i)
{
out << s[i] <<' ';
}
return out;
}
//cout和cin分别是输入输出头文件下的一个ostream类对象和istream类对象;
//流提取
std::istream& operator>>(std::istream& in,string& s)
{
char ch=in.get();//输入流中的函数,每次取一个字符;相当于连空格都可以取到的cin;
while (ch!=' '&&ch != '\n')//只要不读到enter也就是换行符,就一直提取;
{
s += ch;
ch = in.get();
}
return in;//支持连续提取;
}