C++之string类的实现代码及其详解(上)
1. 什么是string类
在 C++ 中,string
是标准库(<string>
)提供的类,用于表示和操作字符串。它是对传统 C 风格字符数组(char[]
)的封装,提供了更安全、便捷的字符串操作功能,如动态内存管理、长度自动跟踪和丰富的成员函数。
同时我们设计了一些接口函数来实现对他的调用。
PS:string在调用的时候只要加头文件含#include头文件以及using namespace std即可。
2. string本身代码实现
我们先把string本身实现一下,然后在它的代码上再添加接口函数。
我们来看下面这个代码,我们先把char*和const char*重命名为iterator和const_iterator是因为这样写更加规范(也显得更加专业)。
class string{public:typedef char* iterator;typedef const char* const_iterator;}
2.1 begin与end
首先我们在private创建了三个成员函数,_str
:指向动态分配的字符数组(以 \0
结尾的 C 风格字符串),_size
:当前字符串的有效字符长度(不包含终止符)和_capacity
:当前分配的内存空间大小(包含终止符位置)。接下来我们实现了普通版本的begin,end和const版本的begin和end。这里我们要理解在const版本的begin和end后面的那个const是指向this指针的。
class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}private:size_t _size;size_t _capacity;char* _str;};
2.2 构造函数
然后我们通过构造函数来实现对string的初始化,在这里我们写成const char* str = ""是为了允许无参调用构造函数,创建空字符串对象(因为不能说初始化为空就直接报错)。我们在capacity后面加2是为了给 \0
留位置同时防止越界访问,同时我们在这里是使用memcpy是为了直接复制指定字节数,这样不容易出现错误。注意我们把str给_str是为了实现初始化的时候赋值,比如说string a1("aaaaaaaaaa")这样。
class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}string(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 2];memcpy(_str, str, _size+1);}private:size_t _size;size_t _capacity;char* _str;};
}
PS:在这里_str是一个指向数组开头元素的指针。
2.3 拷贝构造函数
首先拷贝构造都是传引用返回(为了防止套娃,即递归触发拷贝构造函数)。然后我们给_str开传进来的s.capacity+2个空间,
class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}string(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 2];memcpy(_str, str, _size+1);}string(const string& s){_str = new char[s._capacity + 2];memcpy(_str, s._str,s._size+1);_size = s._size;_capacity = s._capacity;}private:size_t _size;size_t _capacity;char* _str;};
}
PS:各位有没有想过为什么在这里s就可以直接使用capacity呢,为什么在构造函数里面不可以这样,而是要通过strlen呢?简单来说就是因为str是外部传入的,而s是内部类对象所以可以互相访问。
2.4 析构函数
首先我们通过delete来对_str里面的内容进行清理,接着把_str数组置为空(这一步是为了防止出现野指针现象),最后我们把_size和_capacity都置为空。
class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}string(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 2];memcpy(_str, str, _size+1);}string(const string& s){_str = new char[s._capacity + 2];memcpy(_str, s._str,s._size+1);_size = s._size;_capacity = s._capacity;}~string(){delete[]_str;_str = nullptr;_size = _capacity = 0;}private:size_t _size;size_t _capacity;char* _str;};