0. 写在前面的话
在C++入门7——string类使用说明书中,我们已经了解了string类如何使用的一些情况,string类无非就是存在三个私有变量:
一个是string类的容量:size_t _capacity;
一个是string类有效字符的长度:size_t _size;
最后一个是string类的字符数组:char* _str;
现在我们就依据此来模拟实现一下string类的若干需求。
1. string类构造函数的实现
在实现string类构造函数之前,我们应该明确一个问题:string类是需要进行增删查改的,所以对string类构造函数的无参初始化不能简简单单的就将_size和_capacity置为0、将_str只开1字节的空间存'\0',正如下面这个错误示范:
//error: class { public: string() :_str(new char[1]) ,_size(0) ,_capacity(0) { _str[0] = '\0'; } private: }
因此我们采用先动态开辟空间,再调用strcpy函数将实参_str拷贝进形参str,以便于后面的增删查改。
1.1 字符串常量初始化
string(const char* str = " ") { _size = strlen(str);//调用strlen函数计算str的长度 _capacity = _size; _str = new char[_capacity + 1];//_str开空间比_capacity多1是为了存'\0' //先动态开辟空间,再将str写进_str,便于后期的增删查改 strcpy(_str, str);//调用strcpy函数将str拷贝进_str }
1.2 拷贝构造
拷贝构造一:
string(const string& s) { _str = new char[s._capacity + 1]; strcpy(_str, s._str); _size = s._size; _capacity = s._capacity; }
拷贝构造二:(=运算符重载)
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; }
2. 析构函数和计算size、capacity简单函数的实现
①析构函数:
~string() { delete[] _str; _str = nullptr; _size = 0; _capacity = 0; }
②计算size:
size_t size() const { return _size; }
③计算capacity:
size_t capacity() const { return _capacity; }
3. c_str函数
首先我们要知道的是:
c_str()就是将C++的string转化为C的字符串数组,c_str()生成一个const char *指针,指向字符串的首地址。
因为在c语言中没有string类型,必须通过string类对象的成员函数 c_str() 把 string 转换成c中的字符串样式。
所以为了省去重载string类的流插入和流提取运算符,我们直接实现c_str函数,进而利用c_str函数实现打印功能。
//将const string类型转化为const char*类型 const char* c_str() const { return _str; }
4. 访问函数实现
4.1 迭代器iterator
我们知道,迭代器的begin和end是:
begin获取一个有效字符的迭代器 +,end获取最后一个有效字符下一个位置的迭代器
而在C++入门7——string类使用说明书中,我们用到迭代器时:
iterator是一个像指针一样的类型,*it 可以理解为指针的解引用,那么就可以使用解引用来修改字符:
int main() { string s1("hello world!"); string::iterator it = s1.begin(); while (it != s1.end()) { cout << *it << endl; ++it; } return 0; }
依据此我们就可以将string类的iterator理解为指针(当然其底层不完全是指针):
①普通迭代器可读可写:
typedef char* iterator; iterator begin() { return _str; } iterator end() { return _str + _size; }
②const迭代器可读不可写:
typedef const char* const_iterator; const_iterator begin() const { return _str; } const_iterator end() const { return _str + _size; }
4.2 下标+[]访问
①普通函数,可读可写:
char& operator[](size_t pos) { assert(pos <= _size); return _str[pos]; }
②const函数,可读不可写:
const char& operator[](size_t pos) const { assert(pos <= _size);//检查pos是否合法 return _str[pos]; }
5. reserve(提前开空间函数实现)
void reserve(size_t n) { if (n > _capacity) { char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } }
6. 插入函数
6.1 尾插
①push_back函数实现(尾插字符):
void push_back(char ch) { if (_size == _capacity) { size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newCapacity); } _str[_size] = ch; _size++; _str[_size] = '\0'; }
②append插入实现(尾插字符串):
void append(const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } strcpy(_str + _size, str);//将str拷贝进_str的末尾 _size += len; }
6.2 +=运算符重载
①插入字符:
string& operator+=(char ch) { push_back(ch);//复用push_back return *this; }
②插入字符串:
string& operator+=(const char* str) { append(str);//复用append return *this; }
6.3 insert插入实现
①插入字符:
void insert(size_t pos, char ch) { assert(pos <= _size); if (_size == _capacity) { size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newCapacity); } size_t end = _size + 1; while (end > pos) { _str[end] = _str[end - 1]; --end; } _str[pos] = ch; _size++; }
②插入字符串:
void insert(size_t pos, const char* str) { assert(pos <= _size); size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } int end = _size; while (end >= (int)pos) { _str[end + len] = _str[end]; --end; } strncpy(_str + pos, str, len);//用memcpy也可,注意不能再用strcpy,因为strcpy会导致目标缓冲区溢出! _size += len; }
7.删除函数
7.1 pop_back函数实现(尾删)
void pop_back() { assert(_size > 0); _size--; _str[_size] = '\0'; }
7.2 erase函数实现(删除指定位置)
void erase(size_t pos, size_t len = npos) { assert(pos < _size); if (len == npos || pos + len >= _size) { _str[pos] = '\0'; _size = pos; } else { strcpy(_str + pos, _str + pos + len); _size -= len; } }
8. 查找函数
①查找字符:
size_t find(char ch, size_t pos = 0) { for (size_t i = pos; i < _size; i++) { if (_str[i] = ch) { return i; } } return npos; }
②查找字符串:
size_t find(const char* str, size_t pos = 0) { const char* ptr = strstr(_str + pos, str); if (ptr == nullptr) { return npos; } else { return ptr - _str; } }
9.取string子串(substr)函数实现
string substr(size_t pos = 0, size_t len = npos) { assert(pos < _size); size_t end = pos + len; if (len == npos || pos + len >= _size) { end = _size; } string str; str.reserve(end - pos); for (size_t i = pos; i < end; i++) { str += _str[i]; } return str; }
10. 修改(swap)
void swap(string& s) { //调用std库中的swap来实现string的交换函数 std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); }
源代码(string.h):
#pragma once #include <iostream> #include <assert.h> using namespace std; namespace xxk { class string { public: //构造函数实现 //字符串常量初始化 string(const char* str = " ") { _size = strlen(str);//调用strlen函数计算str的长度 _capacity = _size; _str = new char[_capacity + 1];//_str开空间比_capacity多1是为了'\0' //先动态开辟空间,再将str写进_str,便于后期的增删查改 strcpy(_str, str);//调用strcpy函数将str拷贝进_str } //拷贝构造① string(const string& s) { _str = new char[s._capacity + 1]; strcpy(_str, s._str); _size = s._size; _capacity = s._capacity; } //拷贝构造② 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; } //析构函数实现 ~string() { delete[] _str; _str = nullptr; _size = 0; _capacity = 0; } //计算size函数实现 size_t size() const { return _size; } //计算capacity函数实现 size_t capacity() const { return _capacity; } //将const string类型转化为const char*类型 const char* c_str() const { return _str; } //访问函数实现 //迭代器访问 //①普通迭代器 typedef char* iterator; iterator begin() { return _str; } iterator end() { return _str + _size; } //②const迭代器 typedef const char* const_iterator; const_iterator begin() const { return _str; } const_iterator end() const { return _str + _size; } //下标+[]访问 //①const成员函数,可读不可写 const char& operator[](size_t pos) const { assert(pos <= _size);//检查pos是否合法 return _str[pos]; } //②普通成员函数,可读可写 char& operator[](size_t pos) { assert(pos <= _size); return _str[pos]; } //reserve(提前开空间函数实现) void reserve(size_t n) { if (n > _capacity) { char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } //插入函数 //尾插 //①push_back函数实现(尾插字符) void push_back(char ch) { if (_size == _capacity) { size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newCapacity); } _str[_size] = ch; _size++; _str[_size] = '\0'; } //②append插入实现(尾插字符串) void append(const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } strcpy(_str + _size, str);//将str拷贝进_str的末尾 _size += len; } //+=插入实现 //①插入字符 string& operator+=(char ch) { push_back(ch);//复用push_back return *this; } //②插入字符串 string& operator+=(const char* str) { append(str);//复用append return *this; } //insert插入实现 //①插入字符 void insert(size_t pos, char ch) { assert(pos <= _size); if (_size == _capacity) { size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newCapacity); } size_t end = _size + 1; while (end > pos) { _str[end] = _str[end - 1]; --end; } _str[pos] = ch; _size++; } //②插入字符串 void insert(size_t pos, const char* str) { assert(pos <= _size); size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } int end = _size; while (end >= (int)pos) { _str[end + len] = _str[end]; --end; } strncpy(_str + pos, str, len);//用memcpy也可,注意不能再用strcpy,因为strcpy会导致目标缓冲区溢出! _size += len; } //删除函数 //①pop_back函数实现(尾删) void pop_back() { assert(_size > 0); _size--; _str[_size] = '\0'; } //erase函数实现(删除指定位置) void erase(size_t pos, size_t len = npos) { assert(pos < _size); if (len == npos || pos + len >= _size) { _str[pos] = '\0'; _size = pos; } else { strcpy(_str + pos, _str + pos + len); _size -= len; } } //string中swap函数的实现 void swap(string& s) { //调用std库中的swap来实现string的交换函数 std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); } //查找函数find函数实现 //①查找字符 size_t find(char ch, size_t pos = 0) { for (size_t i = pos; i < _size; i++) { if (_str[i] = ch) { return i; } } return npos; } //②查找字符串 size_t find(const char* str, size_t pos = 0) { const char* ptr = strstr(_str + pos, str); if (ptr == nullptr) { return npos; } else { return ptr - _str; } } //取string子串(substr)函数实现 string substr(size_t pos = 0, size_t len = npos) { assert(pos < _size); size_t end = pos + len; if (len == npos || pos + len >= _size) { end = _size; } string str; str.reserve(end - pos); for (size_t i = pos; i < end; i++) { str += _str[i]; } return str; } private: size_t _capacity; size_t _size; char* _str; const static size_t npos = -1; }; }