文章目录
- 一. string底层逻辑
- 二. size()
- 三. operator[]
- 四. 迭代器
- 四. const迭代器
- 五. 预留空间(reserve)
- 六. 尾插一个字符push_back
- 七. 尾插一个字符串append
- 八. operator+=
- 九. operator+=
一. string底层逻辑
(1)为了和库里面的string类区分开,我们可以使用命名空间(hou)。之前学习的命名空间就有了价值。
(2)在类里面的都是内联函数
(3)对于比较短小的函数,直接在类里面写就行。函数大一点,将声明和定义分开。
- 成员变量
#include<stdio.h>
#include<string>
#include<iostream>
namespace hou
{
class string
{
private:
char* _str; //char类型数据数组的地址
size_t _size; //有效元素个数
size_t _capacity; //空间大小
};
}
- 成员函数
任何一个类都从构造函数开始(无参/有参)
无参的话,将三个成员变量初始化为什么呢?都初始化为空吗?
这样是不可以的。
记得:const char*
比较特殊,cout
它不会打印出地址,它自动识别类型,会以为打印字符串(字符串的打印规则是遇到‘\0’
才会终止),而我们的_str
是空指针,将空指针解引用,肯定是错误的(本质是空指针问题)
---------------
所以,不能将char*
初始化为空。里面起码要放一个'\0'
namespace hou
{
class string
{
public:
//任何一个类都从构造函数开始
string()//先写一个无参的构造函数
:_str(new char[1]{'\0'})
,_size(0)
,_capacity(0)
{}
~string()
{
delete[] _str;
_str = nullptr;
_size = 0;
_capacity = 0;
}
const char* c_str()const
{
return _str;
}
private:
char* _str; //char类型数据数组的地址
size_t _size; //有效元素个数
size_t _capacity; //空间大小
};
}
刚刚写了无参的构造函数,接下来写一个有参的构造函数
注意点:
strlen
计算长度时,不包括'\0'
- strlen是在运行时计算的,size是编译时计算的
- 在初始化列表里写,它的初始化顺序是按照声明的顺序来的
之前我们说过,尽可能使用初始化列表,但是strlen是在运行时计算的,要计算3次,效率低。这样子的话,我们可以将strlen先计算出来,之后用。但记住,初始化列表的顺序是按照声明的顺序。
演示声明和定义分开
当我们想把声明写在.h里面,定义写在.cpp里面的时候
这样写会报错,所以我们需要在string.cpp
里(1)写上类域(2)再写一下命名空间
一个命名空间是可以写多个的,多个文件的同一个命名空间会被合并为(认为)一个命名空间的
已经声明和定义了,还有一个需要注意的内容是,缺省值只能在声明的时候给(定义那里不可以写缺省值)。但是char* _str
的缺省值不可以是nullptr
,可以给一个'\0'
或者直接“”
(字符串默认后面会加'\0'
的)
二. size()
对象.size()
就是为了得到对象的大小(即对象的有效元素个数)
如果声明和定义分开写了,同时这个函数有返回值,那string::
加到哪里呢?
三. operator[]
string.cpp里面的内容
char& string::operator[](size_t i)
{
return _str[i];
}
四. 迭代器
string的迭代器(string的物理结构是数组)
using iterator = char*;
//typedef char* iterator;
迭代器还需要配合begin()
和end()
(begin()就是返回开始位置的迭代器)
using iterator = char*;
iterator string::begin()
{
return _str;
}
iterator string::end()
{
return _str+_size;
}
范围for的底层是迭代器(支持迭代器则支持范围for)
四. const迭代器
五. 预留空间(reserve)
本质就是扩容,但是这种提高了效率,原本需要2倍2倍的扩,但是当你知道需要多大的空间时,就可以一次性扩容好。
- reserve一般不缩容,我们需要先判断一下,想扩容的大小n是否比_capacity大
- 开空间的时候永远要多开一个,因为
’\0‘
是不计入_capacity
的
void string:: reserve(size_t n)
{
if (n > _capacity)
{
char* tmp=new char[n+1];
strcpy(tmp, _str);
delete[]_str;
_str = tmp;
_capacity = n; //'\0'不计入空间大小
}
}
六. 尾插一个字符push_back
void string::push_back(char ch)
{
//先判断空间大小是否足够
if (_size = _capacity)
{
//不够的话进入if语句进行扩容
reserve(_capacity = 0 ? 4 : 2 * _capacity);
}
_str[_size] = ch;
_size++;
}
七. 尾插一个字符串append
void string::append(const char* str)
{
size_t len = strlen(str);
size_t newcapacity = 2 * _capacity < _size + len ? _size + len : 2 * _capacity;
reserve(newcapacity);
//开好空间之后,插入字符串
strcpy(_str+_size, str);//直接复制(第一个参数是复制到哪里(位置),第二个是被复制的串)
_size += len;
}
八. operator+=
string& string:: operator+=(char ch)
{
push_back(ch);
return *this;
}
九. operator+=
string& string:: operator+=(const char* str)
{
append(str);
return *this;
}
标签:capacity,string,接口,char,str,operator,模拟,size
From: https://blog.csdn.net/2402_83250773/article/details/143955162