目录
简介
因为世界上有很多种语言,所以在STL库里有一个管理字符的模板类:basic_string模板类,而本篇要讲的string类是basic_string模板类的一个实例化,类型为char。
string类的接口设计是比较冗余的,是因为string类有一些历史包袱。在STL出现之前,就已经有string类了。在STL被惠普实验室开源之后,string类既要符合STL的标准又要向前兼容,所以string类的接口比较冗余。
string类的底层是顺序表,它在堆上开辟连续的空间,并将代码段中的常量字符串进行拷贝。通过顺序表实现对字符串的增删查改。可参考C++的动态内存管理一文:http://t.csdnimg.cn/qHEzj
小编会介绍一些常见的接口,解释它们的功能,参数。然后模拟实现一下。为了方便,小编会调用C语言库中的一些字符串操作函数。头文件string.h
模拟实现不是造一个更好的轮子,而是为了帮助我们更好的理解string类。模拟实现的代码是禁不住在各种场景下测试的,一定会出现各种bug。小编会指出一些能想的到的bug。庖丁解牛,恢恢乎游刃有余
C++是一门面向对象的语言,大家不必对每一个接口都有细致的了解。小编写本篇的目的是为了让大家能对string类的主体框架有一定的了解。让大家在查文档时游刃有余。
框架
为了让类名和接口的写法和库里的保持一致,需要封一层命名空间,名字为MyString。
数据设计:
顺序表的有效数据:size_t _size
顺序表的空间大小:size_t _capacity
指向顺序表的指针:char* _str
static const size_t npos = -1;
npos
是string
类中的一个静态成员变量,它表示一个无效的位置或者未找到的位置。在string
类中,当查找某个子字符串或字符时,如果未找到,则返回npos
。
namespace MyString //命名空间
{
class string //string类
{
public:
//接口(方法)
private:
size_t _size; //数据有效个数
size_t _capacity; //空间大小
char* _str; //指向的空间
static const size_t npos = -1;
};
}
构造
可参考详解构造函数一文:http://t.csdnimg.cn/8Hl5K
功能:构造一个string类对象,并将其初始化
在C++11的标准中,有非常多的构造函数,如下图
模拟实现:
小编先问大家一个问题,当我们用"x\0xxx"字符串构造对象时,有效数据_size应该给成多少呢,1还是5?
可以参考一下标准库里的实现
标准库的逻辑是:在初始化对象时,以第一个"\0'为准。我们就可以调用库中的strlen(),帮我们计算一下要初始化_size的大小。strlen()计算长度时也是以第一个"\0"为准。
后面会有"x\0xxx",但_size是5的情况。因为标准库中的string类的有效数据是以_size为准,而不是以"\0"为准。这是C++的string类和C语言中字符串函数不一样的地方。
全缺省构造函数
代码如下
//全缺省构造
string(const char* str = "")
:_size(strlen(str))
,_capacity(_size + 1)
,_str(new char[_capacity])
{
strcpy(_str, str);
}
传对象构造函数
代码如下
string(const string& str)
:_size(str._size)
, _capacity(str._capacity)
, _str(new char[str._capacity])
{
memcpy(_str, str._str, str._capacity); //这里用strcpy()拷贝会有很坑的bug
}
为什么小编会说用strcpy()拷贝数据会有一个很坑的bug呢?
因为string()是以"\0"为基准作为结束条件的。而string类的顺序表可能会存放"x\0xxx"这样的字符串,数据可能会拷贝不全。
拷贝构造
可参考详解拷贝构造一文:http://t.csdnimg.cn/oJCAU
代码如下
//拷贝构造
string(const string& str)
{
_size = str._s