各位好友,接下来 我们将向 String 模拟实现进行开战 !在本期, 会实现部分常见的 String 类的接口 !
下面, 我们将共同对 String 底层原理进行逐一剖析 !让我们一步步接近 String 类对象的本质与 面纱 !
下面来看源代码 : >
1.头文件 "String.h"
#include <iostream>
namespace UC
{
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;
strcpy(_str, str);
}
~string()
{
delete[]_str;
_str = nullptr;
_size = _capacity = 0;
}
size_t size() const
{
return _size;
}
const char* c_str() const
{
return _str;
}
char& operator[](size_t pos)
{
return _str[pos];
}
const char& operator[](size_t pos) const
{
return _str[pos];
}
//追加字符串
void push_back(char ch)
{
if(_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2); // 自定义扩容函数
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
void append(const char* str)
{
size_t len = strlen(str);
if(len + _size > _capacity)
{
reserve(len + _size);
}
strcpy(len + _str, str);
_size += len;
}
//扩容
void reverse(size_t n)
{
if(n > _capacity)
{
char* tamp = new char[n + 1];
strcpy(tamp, _str);
delete[]_str;
_str = nullptr;
_str = tamp;
_capacity = n;
}
}
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
2.测试环节 "Test.cpp"
#include "String.h"
using std::cout;
using std::endl;
void test_01()
{
UC::string T1("I like music !");
cout << T1.c_str() << endl;
//遍历
for(size_t i = 0; i < T1.size(); i++)
{
cout << T1[i] << " ";
}
cout << endl;
//迭代器
UC::string::iterator it = T1.begin();
while(it != T1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
void test_02()
{
UC::string T1("I like music !");
cout << T1.c_str() << endl;
T1.push_back(' ');
T1.push_back('&');
T1.append("$$$$$$$$$$$");
cout << T1.c_str() <<endl;
}
void test_03()
(
UC::string T1("I like music !");
cout << T1.c_str() << endl;
T1 += ' ';
T1 ++ '*';
T1 += ' ';
T1 ++ "$$$$$$$$";
cout << T1.c_str() << endl;
)
int main()
{
test_0x();
}
为了方便好友们, 有更好地观感体验, 现 附上有彩色的代码图样 !
A.头文件 "String"
测试及运行 :>
(1)No.1
(2)No.2
(3)No.3
下面, 进入解析环节 :>
------------------------------------>有关于初始化列表<-----------------------------------------
错误用法 :>
原因如下 :>
由于初始化列表 ------->初始化过程是按照私有域里面的变量进行的创建
-------------------------------------------->即 有序的初始化 (可以通过调试进行观察)
因此,开辟新空间过程, _capacity 是一个随机值, 而该随机值往往非常大;------>新空间的开辟并不合理 !
正确用法 :>
内置类型 放在初始化列表 影响不大 与放在函数体中初始化都是一样的,但是 自定义类型会有所不同
自定义类型不用去写, 会自动调用它的默认构造函数 自定义类型最好是放在初始化列表进行初始化 !
同时, 回顾一下 ----> 前段时间, 学习的 默认构造函数有哪几种形式 ?(三种)
---------------------------------->无参数 ~~~ 全缺省 ~~~ 不用写自动生成 <-------------------------------------
难点 一 : >
各位好友, 下面对 const 修饰限定进行回顾复习 : >
(1)const 成员函数
此处迭代器位置 :>
运用了 const 修饰符进行限定, 保证普通对象在调用的时候, 能够进行 平移操作 , 同时涉及 权限的缩小 !
注意 : >const 实际上修饰该成员函数隐含的 this 指针(可以省略)
------------------------->表明该成员函数中 不能对类的任何成员进行修改 <--------------------------------
(2)const 形参 ~~ 实参 ---->调用 与传入
------------>而此处 const 添加 为保证数据再 被写入的时候, 只能能够进行 读取, 不能被 修改 !
------------>--------->-------->同时, 涉及到类型匹配, 测试部分的实参环节,输入的是一个常量字符串 !
难点 二 : >size_t
各位好友, 为何此处需要用到 size_t --->首先 size_t 是一个无符号的整形运算符 !
size_t 和 int 都是 C++ 中的数据类型,但是它们有 不同之处。size_t 是一种无符号整数类型,通常用于表示内存中对象的大小或数组的索引。而 int 是一种有符号整数类型,通常用于表示整数值。
由于 size_t 是无符号整数类型,因此它不能表示负数。而 int 可以表示负数。此外,size_t 的大小取决于编译器和操作系统,通常为 32 位或 64 位。而 int 的大小通常为 32 位。
由于 size_t 是无符号类型,因此 不会出现负数,但是在某些情况下可能会发生溢出。
------------->当 size_t 类型的变量达到其最大值时,再增加 “ 1 ” 就会导致溢出。
在大多数平台上,size_t 的最大值是 2^64-1 或 2^32-1,具体取决于编译器和操作系统。
例如,在一个 64 位系统上,如果一个 size_t 类型的变量已经达到了最大值 2^64-1,再进行加一操作就会导致变量的值变为 0,这就是溢出 !
难点 三 : >
----->有关于 模拟实现 string 构造函数
注意:> 空字符串 默认带有一个 结束字符串 '\0' 而结束位置必须有一个结束字符串 ‘\0’
注意上述 字符串的大小计算结果 :>
会发现结束字符 ‘\0’ 被当作了 无效字符处理, strlen()接口实现不会将 ‘\0’进行计算在内 !!
因此, 开辟 空间容纳大小的时候, 需要多开一个字节的空间, 将结束字符 ‘\0’ 包含在内 !毕竟字符串输入之后, 编译器会自动将 ‘\0’添加上 !如此才有 “_str = new char[_capacity + 1]”空间开辟 “+1”说法
下面展现 三种错误用法 : >
(1)缺省参数初始化 为 nullptr(空指针)
---------------------->错误写法 会使得读入字符串的时候,调用 strlen(str) 即会崩溃 <-------------------
(2)缺省参数初始化 结束字符 '\0'(画蛇添足)
----------------------------->此种写法结果是正确的, 但是非常不简洁 !<-----------------------------
(3)缺省参数位置 没有 const
------------------------>第二个原因 :实参字符串 是一个常量 !这点不可以忽视 !<-----------------------------
至此 ,本期博文到此结束 !下一期, 我们将继续探索 string 底层实现原理 !
------>模拟实现 string 插入(insert) 删除(erase) 寻找(find) !------->敬请期待 !‘’😊😊