前言
string是用来管理字符的容器,它在物理上是一个可以动态增长的字符数组,了解string类核心接口的实现对于我们更好的理解string类有很大的帮助,下面让我们一起来实现一下string类的核心接口吧!
目录
1.四个默认成员函数
string(const char* s = "")//默认拷贝函数
: _str(new char[strlen(s) + 1])//开空间
, _size(strlen(s))
, _capacity(strlen(s))
{
strcpy(_str, s);//完成字符的拷贝
}
string(const string& s)//拷贝构造函数
:_str(new char[strlen(s._str) + 1])//开空间
, _size(s._size)
, _capacity(s._capacity)
{
strcpy(_str, s._str);//拷贝字符
}
void swap( string& s)
{
::swap(_str, s._str);
::swap(_size, s._size);
::swap(_capacity,s._capacity);
}
~string()//析构函数
{
delete[]_str;
_str = nullptr;
_size = _capacity = 0;
}
string &operator=(const string& s)
{
if (this != &s)//防止自己给自己赋值
{
//申请新空间
char* newstr = new char[strlen(s._str) + 1];
strcpy(newstr, s._str);//拷贝数据
delete[]_str;//释放旧空间
_str = newstr;
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
注意:拷贝构造函数和operator=有新的不同的写法,如下:
要注意深浅拷贝的问题所以不能直接进行赋值。
string(const string& s)//拷贝构造函数
:_str(nullptr)
, _size(0)
, _capacity(0)
{
string tmp(s._str);
//this->swap(tmp);//调用自己实现的swap
swap(tmp);//调用自己实现的swap
}
void swap( string& s)
{
::swap(_str, s._str);
::swap(_size, s._size);
::swap(_capacity,s._capacity);
}
string& operator=(string s)
{
if (*this != s)//避免对象自己给自己赋值
{
::swap(*this,s);//调用全局的swap函数
return *this;
}
}
现代写法不同于传统的写法,这种写法是借助别人构造的对象实现函数的功能,不需要自己来写,只需要“换来”用就行了。
2.迭代器
string的迭代器是原生的指针。
typedef char* iterator;
typedef const char* const_iterator;
//迭代器
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
//const 迭代器
const_iterator begin()const
{
return _str;
}
const_iterator end()const
{
return _str + _size;
}
3.增删查改
//尾插尾删一个字符
void push_back(const char value)
{
if (_size == _capacity)//扩容
{
size_t len = _capacity == 0 ? 2 : 2 * _capacity;
reserve(len);
}
_str[_size] = value;//插入数据
++_size;//更新size
_str[_size] = '\0';
//insert(_size,value);
}
void pop_back()
{
assert(_size);//字符数组中有数据
--_size;
//erase(_size-1);
}
void append(const char* str)//尾插一个字符串
{
size_t len = strlen(str)+_size;
if (_size + len > _capacity)//扩容
{
//len = (_capacity == 0 ? 2 : len);//考虑string的容量为空的情况
reserve(len);
}
strcpy(_str + _size, str);//插入字符串
_size = len;//更新字符串的长度
}
//任意位置的插入和删除
string& insert(size_t pox,char ch)//插入一个字符
{
assert(pox < _size);//确保位置有效性-尾插也可以
int i = _size;
if (_size == _capacity)//扩容
{
size_t len = (_capacity == 0 ? 2 : 2 * _capacity);
reserve(len);
}
while (i >= (int)pox)//移动数据
{
_str[i + 1] = _str[i];
--i;
}
//插入字符
_str[pox] = ch;
++_size;//更新size
return *this;
}
string& insert(size_t pox,const char* s)//插入字符串
{
assert(pox < _size);//确保位置有效性
size_t len = strlen(s);
if (len + _size > _capacity)//string满了扩容
reserve(len + _size);
int end = _size;
while (end >= (int)pox)//pox与end比较会转换为size_t 为无符号整形,
{
//所以比较的时候必须将pox转换为int,不然头插就停不下来了
_str[end+len] = _str[end];//向后挪动数据
--end;
}
strncpy(_str + pox, s, len);//插入字符串
_size += len;//更新size
return *this;
}
string& erase(size_t pox,size_t len = npos)//删除pox位置的字符
{
assert(pox < _size);
if (len > strlen(_str + pox))
{
_str[pox] = '\0';
_size = pox;
}
else
{
while (pox < (int)_size)//移动数据
{
_str[pox] = _str[pox + len];
++pox;
}
_size -= len;//更新size
}
return *this;
}
string& operator+=(const string& s)
{
append(s._str);
return *this;
}
string& operator+=(const char* s)
{
append(s);
return *this;
}
string& operator+=(const char s)
{
push_back(s);
return *this;
}
4.容量相关
//
size_t size()const//加上const防止_size被改变,同时const对象和非const对象都可以调用
{
return _size;
}
size_t capacity()const//加上const防止_capacity被改变,同时const对象和非const对象都可以调用
{
return _capacity;
}
void reserve(size_t n)//改变容量的函数
{
if (n > _capacity)//增容
{
char* newstr = new char[n + 1];//开新空间
if (_str)//确保str不为空
{
strcpy(newstr,_str);//拷贝数据
delete[] _str;//释放旧空间
}
_str = newstr;//指向新空间
_capacity = n;//给新的容量
}
}
void resize(size_t n, const char ch = '\0')//改变size
{
if (n <(int) _size)//不需要插入字符
{
_str[n] = '\0';
_size = n;
}
else
{
if (n = _capacity)//增容
reserve(n);
while(_size < n)//拷贝字符
{
_str[_size] = ch;
++_size;
}
_str[_size] = '\0';//补'\0'
}
}
5.测试代码
#include"string.h"
void testString1()
{
qyy::string s1;
qyy::string s2("hhhh");
//s2 = s1;
qyy::string s3(s2);
cout << s2;
}
void testString2()
{
qyy::string s1;
s1.push_back('h');
s1.push_back('e');
s1.push_back('l');
s1.push_back('l');
s1.push_back('0');
//s1.pop_back();
s1.append("hahhaakkkkkkkkkkkkkkk");
cout << s1;
}
void testString3()
{
qyy::string s1;
s1 += "hello ";
s1 += "w";
cout << s1;
/*cout << s1.find('s')<<endl;
cout << s1.find('l')<<endl;*/
s1.insert(1, 'k');
s1.insert(5, "qqqqqq");
cout << s1 << endl;
s1.resize(2);
cout << s1 << endl;
s1.resize(20);
cout << s1 << endl;
}
void testString4()
{
qyy::string s1;
cout << s1 << endl;
s1 += "hhhh1234567xxxxxxxxx";
s1.erase(3, 5);
cout << s1 << endl;
cin >> s1;
cout << s1 << endl;
s1.insert(0, "99999");
cout << s1 << endl;
}
6.判断大小 ,输入和输出
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)
{
if (strcmp(_str, s._str) < 0)
return true;
else
return false;
}
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);
}
void getline()
{
while (1)
{
char ch;
cin.get(ch);
if (ch == '\0')
{
break;//结束输入
}
*this += ch;
}
}
ostream& operator<<(ostream& out,const string&s)
{
size_t i = 0;
for (i = 0; i < s.size(); ++i)
{
cout << s[i];
}
cout << endl;
return out;
}
istream& operator>>(istream& in,string &s)
{
while (1)
{
char ch;
//ch = getchar();
in.get(ch);
if (ch == ' ' || ch == '\n')
{
break;
}
s += ch;
}
return in;
}
7.完整代码
#include<iostream>
#include<assert.h>
#include<string.h>
using namespace std;
namespace qyy
{
size_t static npos = -1;
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
string(const char* s = "")//默认拷贝函数
: _str(new char[strlen(s) + 1])//开空间
, _size(strlen(s))
, _capacity(strlen(s))
{
strcpy(_str, s);//完成字符的拷贝
}
//string(const string& s)//拷贝构造函数
// :_str(new char[strlen(s._str) + 1])//开空间
// , _size(s._size)
// , _capacity(s._capacity)
//{
// strcpy(_str, s._str);//拷贝字符
//}
//现代写法
string(const string& s)//拷贝构造函数
:_str(nullptr)
, _size(0)
, _capacity(0)
{
string tmp(s._str);
//this->swap(tmp);//调用自己实现的swap
swap(tmp);//调用自己实现的swap
}
void swap( string& s)
{
::swap(_str, s._str);
::swap(_size, s._size);
::swap(_capacity,s._capacity);
}
~string()//析构函数
{
delete[]_str;
_str = nullptr;
_size = _capacity = 0;
}
//string &operator=(const string& s)
//{
// if (this != &s)//防止自己给自己赋值
// {
// //申请新空间
// char* newstr = new char[strlen(s._str) + 1];
// strcpy(newstr, s._str);//拷贝数据
// delete[]_str;//释放旧空间
// _str = newstr;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
//}
string& operator=(string s)
{
if (*this != s)//避免对象自己给自己赋值
{
::swap(*this,s);//调用全局的swap函数
return *this;
}
}
//迭代器
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
//const 迭代器
const_iterator begin()const
{
return _str;
}
const_iterator end()const
{
return _str + _size;
}
//
size_t size()const//加上const防止_size被改变,同时const对象和非const对象都可以调用
{
return _size;
}
size_t capacity()const//加上const防止_capacity被改变,同时const对象和非const对象都可以调用
{
return _capacity;
}
void reserve(size_t n)//改变容量的函数
{
if (n > _capacity)//增容
{
char* newstr = new char[n + 1];//开新空间
if (_str)//确保str不为空
{
strcpy(newstr,_str);//拷贝数据
delete[] _str;//释放旧空间
}
_str = newstr;//指向新空间
_capacity = n;//给新的容量
}
}
void resize(size_t n, const char ch = '\0')//改变size
{
if (n <(int) _size)//不需要插入字符
{
_str[n] = '\0';
_size = n;
}
else
{
if (n = _capacity)//增容
reserve(n);
while(_size < n)//拷贝字符
{
_str[_size] = ch;
++_size;
}
_str[_size] = '\0';//补'\0'
}
}
//尾插尾删一个字符
void push_back(const char value)
{
if (_size == _capacity)//扩容
{
size_t len = _capacity == 0 ? 2 : 2 * _capacity;
reserve(len);
}
_str[_size] = value;//插入数据
++_size;//更新size
_str[_size] = '\0';
//insert(_size,value);
}
void pop_back()
{
assert(_size);//字符数组中有数据
--_size;
//erase(_size-1);
}
void append(const char* str)//尾插一个字符串
{
size_t len = strlen(str)+_size;
if (_size + len > _capacity)//扩容
{
//len = (_capacity == 0 ? 2 : len);//考虑string的容量为空的情况
reserve(len);
}
strcpy(_str + _size, str);//插入字符串
_size = len;//更新字符串的长度
}
//任意位置的插入和删除
string& insert(size_t pox,char ch)//插入一个字符
{
assert(pox < _size);//确保位置有效性-尾插也可以
int i = _size;
if (_size == _capacity)//扩容
{
size_t len = (_capacity == 0 ? 2 : 2 * _capacity);
reserve(len);
}
while (i >= (int)pox)//移动数据
{
_str[i + 1] = _str[i];
--i;
}
//插入字符
_str[pox] = ch;
++_size;//更新size
return *this;
}
string& insert(size_t pox,const char* s)//插入字符串
{
assert(pox < _size);//确保位置有效性
size_t len = strlen(s);
if (len + _size > _capacity)//string满了扩容
reserve(len + _size);
int end = _size;
while (end >= (int)pox)//pox与end比较会转换为size_t 为无符号整形,
{
//所以比较的时候必须将pox转换为int,不然头插就停不下来了
_str[end+len] = _str[end];//向后挪动数据
--end;
}
strncpy(_str + pox, s, len);//插入字符串
_size += len;//更新size
return *this;
}
string& erase(size_t pox,size_t len = npos)//删除pox位置的字符
{
assert(pox < _size);
if (len > strlen(_str + pox))
{
_str[pox] = '\0';
_size = pox;
}
else
{
while (pox < (int)_size)//移动数据
{
_str[pox] = _str[pox + len];
++pox;
}
_size -= len;//更新size
}
return *this;
}
size_t find(char ch, size_t pos = 0)
{
assert(pos < _size);
char * p=strstr(_str + pos, &ch);
return p - (_str );
}
size_t find(const char *str, size_t pos = 0)
{
assert(pos < _size);
char* p=strstr(_str + pos, str);
if (p == nullptr)
{
return npos;
}
else
{
return p - (_str + pos);
}
}
string& operator+=(const string& s)
{
append(s._str);
return *this;
}
string& operator+=(const char* s)
{
append(s);
return *this;
}
string& operator+=(const char s)
{
push_back(s);
return *this;
}
//c—str
char* c_str()
{
return _str;
}
const char* c_str()const
{
return _str;
}
//
char& operator[](size_t i)
{
assert(i < _size);
return _str[i];
}
const char& operator[](size_t i)const
{
assert(i < _size);
return _str[i];
}
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)
{
if (strcmp(_str, s._str) < 0)
return true;
else
return false;
}
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);
}
void getline()
{
while (1)
{
char ch;
cin.get(ch);
if (ch == '\0')
{
break;//结束输入
}
*this += ch;
}
}
private:
char* _str;
size_t _size;
size_t _capacity;
};
ostream& operator<<(ostream& out,const string&s)
{
size_t i = 0;
for (i = 0; i < s.size(); ++i)
{
cout << s[i];
}
cout << endl;
return out;
}
istream& operator>>(istream& in,string &s)
{
while (1)
{
char ch;
//ch = getchar();
in.get(ch);
if (ch == ' ' || ch == '\n')
{
break;
}
s += ch;
}
return in;
}
}
string就是一个可以动态增长的字符数组,由于比较简单这里就不做过多的讲解了。只要注意深浅拷贝的问题就行。