实现String类
对于如何来实现一个String类,大多数人都会觉得很难,这个时候就有人要问了:
其实是很简单的,对于类这一部分的结构,都有着固定的结构,首先我们将一个简单的结构先敲出来,然后将就像在类的外部写函数一样,挨个的写就行了,首先我们先写一个大致的结构就像下面:
class String{
public:
//==构造函数
String()
{}
//==析构函数
~String()
{}
//==拷贝构造函数
//==拷贝复制函数
private:
//==成员变量
//size:有效字符个数 //这里我们就直接把成员变量直接写入,比较简单,后面也不用单独分出来进行写
size_t _size;
//容量:最大存放字符的个数
size_t _capacity;
char* _data;
};
我上面写出的就是自己写一个类最最最基础的结构,首先你把这个结构记住了,再将你理解到的成员函数填充进去不就完了,一个板块一个板块的进行学习,最后拼接不就完了.这个只适用于String类哦,别记成万能模板了.
下面我们就进行分版块代码学习,最终拼接就可以了.
1.迭代器获取对应元素
关于迭代器我们在之前已经详细的讲过了,其中的接口也好多都进行了实现,有兴趣的可以看之前写的迭代器那一个,其实在这里我们完全没必要使用迭代器,使用就是为了提高我们的效率,再对之前使用迭代器的方式进行一个复习,让我们掌握的多一点.
1.我们在这里使用迭代器,就要先进行一个声明
2.写出利用迭代器的一些简单的函数,方便我们后面的利用
typedef char* iterator; //先进行声明
typedef const char* const_iterator;
iterator begin(){ //迭代器找到首元素
//首元素的位置
return _data;
}
const_iterator begin() const{ //迭代器找到首元素的位置
//第一个元素的位置
return _data;
}
iterator end(){
//最后一个元素的下一个位置
return _data + _size;
}
const_iterator end() const{
//最后一个元素的下一个位置
return _data + _size;
}
2.构造函数
在构造函数这里我们运用了两种方式来进行构造,主要就是让我们能通过多个方法写一个相关的函数,不可能都是同一个把.
//1
String(const char* str = "")
:_size(strlen(str))
, _capacity(_size)
, _data(new char[_size + 1]) //以上都是对于构造函数的一个初始化
{
strcpy(_data, str); //将要输入的字符串拷贝在相关的内存里面
}
//======================================
//2
String(const String& str)
:_size(0)
, _capacity(0)
, _data(nullptr) //以上为初始化
{
String tmp(str._data); //创建一个新的_data
Swap(tmp); //调用Swap函数
}
//交换函数
void Swap(String& str){ //引用的使用
//对原来内部的大小,容量,以及内存全部进行交换,完全交换成一个新的
swap(_size, str._size);
swap(_capacity, str._capacity);
swap(_data, str._data);
}
上面两种方法都是可以的,主要理解其中的意思就可以了
3.赋值运算符
对于被赋值有不同的接口,我们挨个进行书写.(里面有用多种方法实现的)
1) =
String& operator=(String str){
Swap(str); //直接将上面的函数进行调用即可
return *this;
}
2) [ ]
char& operator[](size_t pos){
assert(pos < _size); //assert 函数相当于不满足条件,发现错误直接中断
return _data[pos]; //返回对应的位置
}
3) [ ]
const型的直接无法改变
const char& operator[](size_t pos) const{
assert(pos < _size);
return _data[pos];
}
4) +=
String& operator+=(const String& str){ //String类类型
append(str._data); //对于+=的操作就相当于进行了一个尾插的作用,直接对你写好的进行调用就可以了
return *this;
}
5) +=
String& operator+=(const char* str){ //字符串类型
append(str);
return *this;
}
6) +=
String& operator+=(const char ch){ //单个字符的类型
pushBack(ch);
return *this;
}
这个版块并不是很难,但是主要你要区分String类的对象/字符串/和单个字符三种的对应方式
4.析构函数
析构函数这就没有什么多说的,进行挨个的删除就可以了
~String(){
if (_data){
delete[] _data; //删除操作
_data = nullptr; //指针为空
_size = _capacity = 0; //内存全部变为0
}
}
5.相关的操作功能的实现
这里对于String类的部分常用接口进行实现
1)pushBack
在一个字符串的尾部添加上对应得数据
void pushBack(const char& ch){
if (_size == _capacity){ //先判断其内存的容量是否够用
size_t newC = _capacity == 0 ? 15 : 2 * _capacity; //不够用则按照对应方式来进行扩容
reserve(newC); //调用已经写好的容量修改函数
}
_data[_size] = ch; //在之前的字符后main进行添加,挨个进行++
++_size;
_data[_size] = '\0'; //进行++后将最后一位变成\0
}
2)reserve
修改容量:只进行容量的增加,不能减小
void reserve(size_t n){
if (n > _capacity){ //当需要扩容的内存大于现有内存的时候再进行扩容
char* tmp = new char[n + 1]; //定义新的字符串
strcpy(tmp, _data); //进行拷贝
delete[] _data; //删除原来的字符串
_data = tmp; //指向新创建的
_capacity = n; //容量变大
}
}
3)resize
用来修改有效字符的个数
void resize(size_t n, const char& ch = '\0'){
if (n > _capacity){ //容量小于N的时候
reserve(n); //调用reserve函数
}
if (n > _size) //当要增大有效复个数的时候
memset(_data + _size, ch, sizeof(char)*(n - _size)); //执行memset操作
_size = n; //更新
_data[_size] = '\0'; //最后一位要指向\0这样字符串才能结束
}
4)append
类似于合并的操作,将两个字符串进行合并
void append(const char* str){
int len = strlen(str); //先确定长度
if (_size + len > _capacity){ //在所需要的内存比较小的时候
reserve(_size + len); //进行扩容操作
}
memcpy(_data + _size, str, sizeof(char)* len); //将需要合并的字符串拷贝进来
_size += len; //更新长度
_data[_size] = '\0'; //最后一位必须是\0,确保字符串的结束
}
5)print
三种不同的打印函数:
普通打印:
void printString(const String& str){ //简单引用操作
for (int i = 0; i < str.size(); ++i){ //for循环
cout << str[i] << " "; //挨个进行输出
}
cout << endl;
}
字符串类进行打印:
void printFor(const String& str){
for (const char& ch : str){ //范围确定
cout << ch << " "; //打印
}
cout << endl;
}
迭代器进行打印:
void printIterator(const String& str){
String::const_iterator it = str.begin(); //迭代器确认开始位置
while (it != str.end()){ //在没有遍历到最后一位的时候
cout << *it << " "; //进行解引用输出
++it; //依次++
}
cout << endl;
}
6)String类与String类/字符串/单个字符相加
String类+String类
String operator+(const String& str1, const String& str2){
//这里的=和+=都是调用了之前我们写的赋值运算符
String str = str1;
str += str2; //String类之间直接相等使用
return str;
}
String类+字符串
String operator+(const char* str1, const String& str2){
String str(str1);
str += str2; //字符串就需要将其包裹在一个类里面
return str;
}
String类+单个字符
String operator+(const char ch, const String& str2){
String str = str2;
str += ch; //也需要将单个字符包裹在新的String类里面才能使用
return str;
}
就这样分区域的样子进行分布代码的书写,多敲几次,理清自己的思路,你也就是大佬了!加油!