模拟实现string只是仿造库里的功能模拟实现,并不和库中代码一样。需要知道的是,string在不同的编译器下,string的实现也是有差异的。
#pragma once
#include
namespace QiBL
{
class string
{
public:
typedef char* iterator;//将iterator写在类里面,这样每一个类都有自己的iterator,所以使用的时候要指定是哪个类的迭代器,迭代器像指针但是可能不是指针
typedef const char* const_iterator;
iterator begin()//begin指向头
{
return _str;
}
iterator end()//end指向尾的下一个,即"\0"
{
return _str + _size;
}
const_iterator begin() const//begin指向头
{
return _str;
}
const_iterator end() const//end指向尾的下一个,即"\0"
{
return _str + _size;
}
public:
string(const char* str = "")//空串自动保留一个"\0",不能使用nullptr,不然在c_str函数返回会报错
//:_str(new char[1])//开一个空间存"\0"标识符
//, _size(0)//_size表示存了多少数据 不算"\0"
//, _capacity(0)//_capacity表示能存多少数据 不算"\0"
: _size(strlen(str))
{
_capacity = _size;//最开始_capacity与_size大小相同,都是初始化的大小,不包含"\0"
_str = new char[_capacity + 1];//strlen计算字符串大小的时候不算"\0",所以开空间的时候多加了1
strcpy(_str, str);
}
/*string(const string& s)
{
_str = new char[s._capacity + 1];
_size = s._size;
_capacity = s._capacity;
strcpy(_str, s._str);
}*/
string(const string& s)
{
string tmp(s._str);
swap(tmp);
}
char* c_str() const
{
return _str;
}
size_t size() const//加const,保证const对象也能调用
{
return _size;
}
size_t capacity() const//加const,保证const对象也能调用
{
return _capacity;
}
char& operator[](size_t i)//为了可读可写,所以使用引用返回,因为在堆上,所以函数结束数据还在
{
assert(i < _size);
return _str[i];
}
const char& operator[](size_t i) const//只读,加const,保证const对象也能调用
{//前面加const是为了返回值是引用,会被其他引用改变返回位置的值
assert(i < _size);
return _str[i];
}
void reserve(size_t n)//扩容
{
if (n > _capacity)//n比_capacity大才扩容,否则不变,不能缩容
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
void push_back(char c)//尾插一个字符
{
if (_size == _capacity)
reserve(_capacity == 0 ? 4 : _capacity * 2);
_str[_size] = c;
++_size;
_str[_size] = '\0';
}
void append(const char* str)//尾插一个字符串
{
size_t len = strlen(str);
if ((_size + len) > _capacity)
{
reserve(_size + len);
}
strcpy(_str + _size, str);//strcpy会将'\0',也拷贝过来
_size += len;
}
string& operator+=(char c)
{
push_back(c);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
/*string& operator=(const string& s)
{
char* tmp = new char[s._capacity + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
return *this;
}*/
string& operator=(string s)
{
swap(s);
return *this;
}
void insert(size_t pos, char c)//在pos前插入字符c,下表从0开始,0是头插,等于_size就是尾插
{
assert(pos <= _size);
if (_size == _capacity)
reserve(_capacity == 0 ? 4 : _capacity * 2);
size_t end = _size + 1;//end指向'\0'的下一个
while (pos < end)
{
_str[end] = _str[end - 1];
--end;
}
_str[pos] = c;
++_size;
}
void insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if ((_size + len) > _capacity)
reserve(_size + len);
size_t end = _size + len;
//while (end - len > pos - 1)//pos可能是0,所以要写为加
while (end > pos + len - 1)
{
_str[end] = _str[end - len];
--end;
}
strncpy(_str + pos, str, len);
_size = _size + len;
}
void erase(size_t pos = 0, size_t len = npos)//从pos位置删除len个
{
assert(pos < _size);//位置是 0 - size - 1
//if (len == npos || pos + len >= _size)//这样写有BUG,有溢出的风险,假设len = nops - 1
if (len == npos || len >= _size - pos)//这种写法可以规避掉风险
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size = _size - len;
}
}
void resize(size_t n, char c = '\0')//改变有效数据的大小,但是不缩容
{
if (n <= _size)
{
_str[n] = '\0';
_size = n;
}
else
{
reserve(n);
for (size_t i = _size; i < n; i++)
{
_str[i] = c;
}
_size = n;
_str[_size] = '\0';
}
}
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
size_t find(char ch, size_t pos = 0)//指定位置开始,找字符返回下标,找不到就返回npos
{
assert(pos < _size);
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == ch)
return i;
}
return npos;
}
size_t find(const char* sub, size_t pos = 0)//指定位置开始,找字符串返回下标,找不到就返回npos
{
assert(pos < _size);
char* p = strstr(_str + pos, sub);//strstr是C语言库中匹配字符串的库函数
if (p)
{
return p - _str;
}
return npos;
}
string substr(size_t pos = 0, size_t n = npos)//指定位置取长度为n的字符串
{
assert(pos < _size);
string s;
if (n >= _size - pos)//从下标0开始
{
for (size_t i = pos; i < _size; i++)
{
s += _str[i];
}
}
else
{
for (size_t i = pos; i < pos + n; i++)
{
s += _str[i];
}
}
return s;
}
void clear()
{
_str[0] = '\0';
_size = 0;
}
~string()
{
delete[] _str;
_str = nullptr;
_size = 0;
_capacity = 0;
}
private:
char* _str = nullptr;
size_t _size = 0;
size_t _capacity = 0;
public:
static const int npos;
};
bool operator==(const string& s1, const string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret == 0;
}
bool operator<(const string& s1, const string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());//s1小于s2返回-1
return ret < 0;
}
bool operator<=(const string& s1, const string& s2)
{
if (s1 < s2 || s1 == s2)
return true;
else
return false;
}
bool operator>(const string& s1, const string& s2)
{
if (s1 <= s2)
return false;
else
return true;
}
bool operator>=(const string& s1, const string& s2)
{
if (s1 < s2)
return false;
else
return true;
}
ostream& operator<<(ostream& out, const string& s)
{
for (auto s : s)
{
out << s;
}
return out;
}
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch;
//in >> ch;//C++的cin和C语言的scanf不支持提取空格和换行
ch = in.get();//推荐使用istream类的get(),类似get char(),但是更好
while (ch != ' ' && ch != '\n')
{
s += ch;
ch = in.get();
}
return in;
}
istream& getline(istream& in, string& s)//一次输入一行内容
{
s.clear();
char ch;
//in >> ch;//C++的cin和C语言的scanf不支持提取空格和换行
ch = in.get();//推荐使用istream类的get(),类似get char(),但是更好
while (ch != '\n')
{
s += ch;
ch = in.get();
}
return in;
}
const int string::npos = -1;
void Stringtest1()
{
string s1 = "Hello World";
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
s1[1] = 'W';
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
string s2 = "Wello World";
for (int i = 0; i < s2.size(); i++)
{
cout << s2[i] << " ";
}
cout << endl;
cout << "Stringtest1()" << endl;
}
void Stringtest2()
{
string s3 = "Hello World";
string::iterator i3 = s3.begin();
while (i3 != s3.end())
{
(*i3)++;
cout << *i3 << " ";
i3++;
}
cout << endl;
for (auto i : s3)//经尝试,范围for只识别begin和end,当iterator换成其他宏,只要begin和end在就能使用,且begin和end的大小写不能换
{//范围for底层是一个死板的替换,并不神秘
i--;
cout << i << " ";
}
cout << endl;
cout << "Stringtest2()" << endl;
}
void Stringtest3()
{
const string s4 = "Hello World";
string::const_iterator i4 = s4.begin();
while (i4 != s4.end())
{
//(*i4)++;
cout << *i4 << " ";
i4++;
}
cout << endl;
//虽然s4被const修饰,但是范围for得到的是s4的拷贝,所以修改的也是临时变量的值,所以不会报错
/*for (auto& i : s4)
{
i--;
cout << i << " ";
}
cout << endl;*/
//
for (auto& i : s4)//范围for使用引用就不是拷贝了
{//综上可以看出,范围for是相当于函数传参一般
//i--;
cout << i << " ";
}
cout << endl;
cout << "Stringtest3()" << endl;
}
void Stringtest4()
{
string s4 = "Hello World";
s4.push_back('H');
cout << s4.c_str();
cout << endl;
cout << "Stringtest4()" << endl;
}
void Stringtest5()
{
string s4 = "Hello World";
s4 += "XYZ";
s4 += "QBL";
s4 += "Q";
cout << s4.c_str()<< endl;
cout << "Stringtest5()" << endl;
}
void Stringtest6()
{
string s4 = "Hello World";
s4.insert(11, 'Q');
cout << s4.c_str() << endl;
cout << "Stringtest6()" << endl;
}
void Stringtest7()
{
string s4 = "Hello World";
s4.insert(0, "QQQ");
cout << s4.c_str() << endl;
cout << "Stringtest7()" << endl;
}
void Stringtest8()
{
string s4 = "Hello World";
s4.erase(10);
cout << s4.c_str() << endl;
cout << "Stringtest8()" << endl;
}
void Stringtest9()
{
string s4 = "Hello World";
s4.resize(5);
cout << s4.c_str() << endl;
s4.resize(10, 'x');
cout << s4.c_str() << endl;
cout << "Stringtest9()" << endl;
}
void Stringtest10()
{
string s4 = "Hello World";
string s5 = s4;
cout << s4.c_str() << endl;
s5.erase(5, 3);
cout << s5.c_str() << endl;
cout << "Stringtest10()" << endl;
}
void Stringtest11()
{
string s4 = "Hello World";
string s5 = s4.substr(10);
cout << s5.c_str() << endl;
cout << "Stringtest11()" << endl;
}
void Stringtest12()
{
string s4 = "Hello World";
string s5 = "Hello World";
cout << (s5 == s4) << endl;
cout << "Stringtest12()" << endl;
}
void Stringtest13()
{
string s4 = "Hello World";
string s5 = "Hello World1";
cout << (s5 == s4) << endl;
cout << (s5 > s4) << endl;
cout << (s5 < s4) << endl;
cout << (s5 >= s4) << endl;
cout << (s5 <= s4) << endl;
cout << "Stringtest13()" << endl;
}
void Stringtest14()
{
string s4 = "Hello World";
cout << s4 << endl;
cout << "Stringtest14()" << endl;
}
void Stringtest15()
{
string s4 = "Hello World";
cout << s4 << endl;
string s5 = "Hello World";
cout << s4 << endl;
cin >> s4 >> s5;
cout << s4 << endl;
cout << s5 << endl;
cout << "Stringtest15()" << endl;
}
void Stringtest16()
{
string s4 = "Hello World";
cout << s4 << endl;
getline(cin, s4);
cout << s4 << endl;
cout << "Stringtest16()" << endl;
}
}