【C++】—— string模拟实现

努力学习的小廉 2024-10-01 10:05:09 阅读 56

前言:

        学习了string的使用,总感觉了解不是很深厚;自己模拟实现string类来帮助自己理解。

        这里只是实现了一部分内容(并没有实现完整的string类)。

先来实现string类里面的成员变量:

<code>#include<iostream>

namespace HL

{

class string

{

public:

private:

char* _str;

size_t _size;

size_t _capacity;

const static size_t npos;

};

const size_t HL::string::npos = -1;

}

一、string默认成员函数(构造、析构、赋值运算符重载)

        1.1、构造函数

1> 默认构造

        默认构造函数就是不需要传参的构造函数;这里实现就开辟一个字符的空间存放 '\0'即可(_capacity不包括 '\0' )。

string()

{

_str = new char[1];

_str[0] = '\0';

_size = 0;

_capacity = 0;

}

2> 拷贝构造

        拷贝构造,在实现时需要注意:是深拷贝,而不是浅拷贝(值拷贝)。

深拷贝(深拷贝简单来说就是,要开辟一块新的空间,把原空间里的值拷贝到新的空间里)。

string(const string& str)

{

_str = new char[str._capacity + 1];

memcpy(_str, str._str, str._size + 1);

_size = str._size;

_capacity = str._capacity;

}

3> 其他构造

        其他构造函数就有很多了,这里就实现以下这几个:

        string (const char* s);

<code>string(const char* s)

{

size_t len = strlen(s);

_str = new char[len + 1];

memcpy(_str, s, len + 1);

_size = len;

_capacity = len;

}

        string (const char* s, size_t n);

string(const char* s, size_t n)

{

size_t len = strlen(s);

if (n > len)

{

n = len;

}

_str = new char[n + 1];

memcpy(_str, s, n);

_str[n] = '\0';

_size = n;

_capacity = n;

}

        string (size_t n, char c);

string(size_t n, char c)

{

_str = new char[n + 1];

for (size_t i = 0; i < n; i++)

{

_str[i] = c;

}

_str[n] = '\0';

_size = n;

_capacity = n;

}

        1.2、析构函数

        析构函数比较简单,释放开辟的资源即可;

~string()

{

delete[] _str;

_str = nullptr;

_size = _capacity = 0;

}

        1.3、赋值运算符重载     

        赋值运算符有3个重载,这里就一一实现:

        string& operator= (const string& str );

实现这个有很多种方法,

        可以释放原空间,再开辟新的空间,将数据拷贝到新的空间中去

<code>string& operator=(const string& str)

{

delete[] _str;

_str = new char[str._capacity];

memcpy(_str, str._str, str._size + 1);

_size = str._size;

_capacity = str._capacity;

return *this;

}

可以调用拷贝构造,构造一个tmp、再将tmp与*this 中的值进行交换(要实现交换函数)

template <typename T>

void Swap(T& x, T& y)

{

T tmp = x;

x = y;

y = tmp;

}

string& operator= (const string& str)

{

string tmp(str);

Swap(_str, tmp._str);

Swap(_size, tmp._size);

Swap(_capacity, tmp._capacity);

return *this;

}

这里如果已经实现string类swap成员函数,就可以直接调用。

        string& operator= (const char* s );        

/*string& operator= (const char* s)

{

size_t len = strlen(s);

delete[] _str;

_str = new char[len + 1];

memcpy(_str, s, len + 1);

_size = _capacity = len;

return *this;

}*/

string& operator= (const char* s)

{

string tmp(s);

Swap(_str, tmp._str);

Swap(_size, tmp._size);

Swap(_capacity, tmp._capacity);

return *this;

}

        string& operator= (char c );

string& operator= (char c)

{

delete[] _str;

_str = new char[2];

_str[0] = c;

_str[1] = '\0';

_size = _capacity = 1;

return *this;

}

二、元素访问与迭代器

        2.1、迭代器

        迭代器,虽然在string类中使用的不是很多,但在后面的容器中有大用处。

        (在string类中就可以简单的理解成指针)。

//迭代器

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);

}

        实现了迭代器之后,范围for这个语法糖就可以使用了(底层就是迭代器)。        

        2.2、下标访问元素

        实现下标访问,就是 [ ]运算符重载。

<code>//下标访问 [ ]

char& operator[] (size_t pos)

{

assert(pos >= _size);

return *(_str + pos);

}

const char& operator[] (size_t pos) const

{

assert(pos >= _size);

return *(_str + _size);

}

        at函数和 [ ] 运算符重载原理一样,这里就不重复写了。

三、增删查改

        在实现增之前,要先实现一个函数,就是调整空间大小的(扩容来用)。

//扩容

void reserve(size_t n)

{

if (n > _capacity)

{

char* s = new char[n + 1];

memcpy(s, _str, _size);

delete[] _str;

_str = s;

_capacity = n;

}

}

        增删这里就实现这些成员函数。

        1、push_back  、append 、operator+=

append重载比较多,这里就实现其中的几个。

<code>//扩容

void reserve(size_t n)

{

if (n > _capacity)

{

char* s = new char[n + 1];

memcpy(s, _str, _size);

delete[] _str;

_str = s;

_capacity = n;

}

}

//增

void push_back(char c)

{

if (_size >= _capacity)

{

reserve((_capacity == 0) ? 4 : 2 * _capacity);

}

_str[_size] = c;

_size++;

_str[_size] = '\0';

}

void append(const string& str)

{

size_t n = _size + str._size;

if (n > _capacity)

{

reserve(n);

}

for (int i = 0; i < str._size; i++)

{

_str[_size + i] = str._str[i];

}

_size += str._size;

_str[_size] = '\0';

}

void append(const char* s)

{

size_t len = strlen(s);

int n = _size + len;

if (n > _capacity)

{

reserve(n);

}

for (int i = 0; i < len; i++)

{

_str[_size + i] = s[i];

}

_size = n;

_str[_size] = '\0';

}

void append(size_t n, char c)

{

if (_size + n > _capacity)

{

reserve(_size + n);

}

for (int i = 0; i < n; i++)

{

_str[_size + i] = c;

}

_size += n;

_str[_size] = '\0';

}

string& operator+=(const string& str)

{

this->append(str);

return *this;

}

string& operator+=(const char* s)

{

this->append(s);

return *this;

}

string& operator+=(char c)

{

this->push_back(c);

return *this;

}

        2、insert、erase

        insert重载也比较多,比较冗余;这里也只实现其中的一部分;

        erase这里只实现一个

<code>//insert 、erase

void insert(size_t pos, const string& str)

{

assert(pos >= 0 && pos < _size);

size_t len = str._size;

size_t n = _size + len;

if (n > _capacity)

{

reserve(n);

}

//挪动数据

for (size_t i = n; i >= pos + len; i--)

{

_str[i] = _str[i - len];

}

memcpy(_str + pos, str._str, str._size);

_size += str._size;

_str[_size] = '\0';

}

void insert(size_t pos, const char* s)

{

assert(pos >= 0 && pos < _size);

size_t len = strlen(s);

size_t n = _size + len;

if (n > _capacity)

{

reserve(n);

}

//挪动数据

for (size_t i = n; i >= pos + len; i--)

{

_str[i] = _str[i - len];

}

memcpy(_str + pos, s, len);

_size += len;

_str[_size] = '\0';

}

void insert(size_t pos, size_t n, char c)

{

assert(pos >= 0 && pos < _size);

if (_size + n > _capacity)

{

reserve(_size + n);

}

//挪动数据

for (size_t i = _size+n; i >= pos + n; i--)

{

_str[i] = _str[i - n];

}

for (size_t i = 0; i < n; i++)

{

_str[pos + i] = c;

}

_size += n;

_str[_size] = '\0';

}

void erase(size_t pos, size_t len = npos)

{

assert(pos >= 0 && pos < _size);

if (len == npos)

{

_str[0] = '\0';

_size = 0;

return;

}

for (size_t i = pos; (len + i) < _size; i++)

{

_str[i] = _str[i + len];

}

_size -= len;

_str[_size] = '\0';

}

        3、find

//find

size_t find(const string& str, size_t pos = 0)

{

assert(pos >= 0 && pos < _size);

char* tmp = strstr(_str + pos, str._str);

if (tmp == nullptr)

{

return -1;

}

return tmp - _str;

}

size_t find(const char* s, size_t pos = 0)

{

assert(pos >= 0 && pos < _size);

char* tmp = strstr(_str + pos, s);

if (tmp == nullptr)

{

return -1;

}

return tmp - _str;

}

size_t find(char c, size_t pos = 0)

{

assert(pos >= 0 && pos < _size);

for (size_t i = pos; i < _size; i++)

{

if (_str[i] == c)

{

return i;

}

}

return -1;

}

        4、swap

        swap作为string的成员函数,交换两个string类类型的对象。

//swap

void swap(string& str)

{

Swap(_str, str._str);

Swap(_size, str._size);

Swap(_capacity, str._capacity);

}

        这里swap函数内部也可以调用库里面的swap模版(这里我自己写了一个模版Swap)

有了swap函数,上面赋值运算符重载中就可以这样写了:

string& operator= (const string& str)

{

string tmp(str);

swap(tmp);

return *this;

}

四、字符串操作函数

        1、c_str

        c_str()函数返回string类对象中的字符串;

const char* c_str() const

{

return _str;

}

char* c_str()

{

return _str;

}

        2、substr

        获得,sting对象中字符串的子串。

<code>//substr

string substr(size_t pos = 0, size_t len = npos) const

{

assert(pos >= 0 && pos < _size);

size_t n = 0;

if (len == npos || pos + len > _size)

{

n = _size - pos;

}

else

{

n = len;

}

string ret;

for (size_t i = 0; i < n; i++)

{

ret += _str[pos + i];

}

return ret;

}

五、其他成员函数

        

        这里max_size是返回容器可以容纳的最大元素的数量,这里就不进行实现了。

reserve在增加元素前已经实现了。(扩容)

<code>//其他成员函数

size_t size() const

{

return _size;

}

size_t length()const

{

return _size;

}

size_t capacity()const

{

return _capacity;

}

void clear()

{

_str[0] = '\0';

_size = 0;

}

bool empty()const

{

return _size == 0;

}

void resize(size_t n)

{

if (n > _capacity)

{

reserve(n);

}

_size = n;

_str[_size] = '\0';

}

void resize(size_t n, char c)

{

if (n > _capacity)

{

reserve(n);

}

for (size_t i = _size; i < n; i++)

{

_str[i] = c;

}

_size = n;

_str[_size] = '\0';

}

        

六、流插入、流提取

        因为成员函数有一个隐藏的this指针,会和istream 和istream 类对象抢占第一个参数的位置,所以我们不能将流插入和流提取写成string类的成员函数。

        string中实现了访问元素方成员函数,就可以不将流插入、流提取写成string类的友元函数。

        1、流插入运算符重载

std::ostream& operator<<(std::ostream& out, const HL::string& str)

{

//for (int i = 0; i < str.size(); i++)

//{

//out << str[i];

//}

//return out;

for (auto ch : str)

{

out << ch;

}

return out;

}

        2、流提取运算符重载

        1、 s.clear()清理缓冲区(上次cin流提取的剩余);

        2、 创建一个数组,防止多次去开空间(输入到128或者输入结束(‘ ’或者‘\n’)才添加到str中)。

        3、下面的代码处理缓冲区的空格。

        char ch;

        ch = in.get();

        while (ch == ' ' || ch == '\n')

        {

            ch = in.get();

        }

        4、最后循环里if是遇到空格或者换行结束,将s中输入添加到s中,末尾添加'\0'。

       

std::istream& operator>>(std::istream& in, HL::string& str)

{

char s[128] = { 0 };

char ch;

ch = in.get();

while (ch == ' ' || ch == '\n')

{

ch = in.get();

}

str.clear();

int i = 0;

while (ch != '\n')

{

s[i] = ch;

i++;

if (i == 127)

{

s[i] = '\0';

str += s;

i = 0;

}

ch = in.get();

}

if (i)

{

str += s;

}

return in;

}

HL :: string 源码

 

#pragma once

#include<iostream>

#include<cassert>

template <typename T>

void Swap(T& x, T& y)

{

T tmp = x;

x = y;

y = tmp;

}

namespace HL

{

class string

{

friend std::ostream& operator<<(std::ostream& out, const HL::string& str);

friend std::istream& operator>>(std::istream& in, HL::string& str);

public:

//构造函数

/*string()

{

_str = new char[1];

_str[0] = '\0';

_size = 0;

_capacity = 0;

}

string(char ch)

{

_str = new char[1];

_str[0] = ch;

_size = 0;

_capacity = 0;

}*/

string(char ch = '\0')

{

_str = new char[2];

_str[0] = ch;

_str[1] = '\0';

_size = 1;

_capacity = 1;

}

string(const char* s)

{

size_t len = strlen(s);

_str = new char[len + 1];

memcpy(_str, s, len + 1);

_size = len;

_capacity = len;

}

string(const char* s, size_t n)

{

size_t len = strlen(s);

if (n > len)

{

n = len;

}

_str = new char[n + 1];

memcpy(_str, s, n);

_str[n] = '\0';

_size = n;

_capacity = n;

}

string(const string& str)

{

_str = new char[str._capacity + 1];

memcpy(_str, str._str, str._size + 1);

_size = str._size;

_capacity = str._capacity;

}

string(size_t n, char c)

{

_str = new char[n + 1];

for (size_t i = 0; i < n; i++)

{

_str[i] = c;

}

_str[n] = '\0';

_size = n;

_capacity = n;

}

~string()

{

delete[] _str;

_str = nullptr;

_size = _capacity = 0;

}

/*string& operator=(const string& str)

{

delete[] _str;

_str = new char[str._capacity];

memcpy(_str, str._str, str._size + 1);

_size = str._size;

_capacity = str._capacity;

return *this;

}*/

/*string& operator= (const string& str)

{

string tmp(str);

Swap(_str, tmp._str);

Swap(_size, tmp._size);

Swap(_capacity, tmp._capacity);

return *this;

}*/

string& operator= (const string& str)

{

string tmp(str);

swap(tmp);

return *this;

}

/*string& operator= (const char* s)

{

size_t len = strlen(s);

delete[] _str;

_str = new char[len + 1];

memcpy(_str, s, len + 1);

_size = _capacity = len;

return *this;

}*/

string& operator= (const char* s)

{

string tmp(s);

Swap(_str, tmp._str);

Swap(_size, tmp._size);

Swap(_capacity, tmp._capacity);

return *this;

}

string& operator= (char c)

{

delete[] _str;

_str = new char[2];

_str[0] = c;

_str[1] = '\0';

_size = _capacity = 1;

return *this;

}

//string& operator= (char c)

//{

//string tmp(c);

//Swap(_str, tmp._str);

//Swap(_size, tmp._size);

//Swap(_capacity, tmp._capacity);

//return *this;

//}

//迭代器

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);

}

//下标访问 [ ]

char& operator[] (size_t pos)

{

assert(pos >= 0 && pos < _size);

return *(_str + pos);

}

const char& operator[] (size_t pos) const

{

assert(pos >= 0 && pos < _size);

return *(_str + _size);

}

//扩容

void reserve(size_t n)

{

if (n > _capacity)

{

char* s = new char[n + 1];

memcpy(s, _str, _size);

delete[] _str;

_str = s;

_capacity = n;

}

}

//增

void push_back(char c)

{

if (_size >= _capacity)

{

reserve((_capacity == 0) ? 4 : 2 * _capacity);

}

_str[_size] = c;

_size++;

_str[_size] = '\0';

}

void append(const string& str)

{

size_t n = _size + str._size;

if (n > _capacity)

{

reserve(n);

}

for (int i = 0; i < str._size; i++)

{

_str[_size + i] = str._str[i];

}

_size += str._size;

_str[_size] = '\0';

}

void append(const char* s)

{

size_t len = strlen(s);

size_t n = _size + len;

if (n > _capacity)

{

reserve(n);

}

for (int i = 0; i < len; i++)

{

_str[_size + i] = s[i];

}

_size = n;

_str[_size] = '\0';

}

void append(size_t n, char c)

{

if (_size + n > _capacity)

{

reserve(_size + n);

}

for (int i = 0; i < n; i++)

{

_str[_size + i] = c;

}

_size += n;

_str[_size] = '\0';

}

string& operator+=(const string& str)

{

this->append(str);

return *this;

}

string& operator+=(const char* s)

{

this->append(s);

return *this;

}

string& operator+=(char c)

{

this->push_back(c);

return *this;

}

//insert 、erase

void insert(size_t pos, const string& str)

{

assert(pos >= 0 && pos < _size);

size_t len = str._size;

size_t n = _size + len;

if (n > _capacity)

{

reserve(n);

}

//挪动数据

for (size_t i = n; i >= pos + len; i--)

{

_str[i] = _str[i - len];

}

memcpy(_str + pos, str._str, str._size);

_size += str._size;

_str[_size] = '\0';

}

void insert(size_t pos, const char* s)

{

assert(pos >= 0 && pos < _size);

size_t len = strlen(s);

size_t n = _size + len;

if (n > _capacity)

{

reserve(n);

}

//挪动数据

for (size_t i = n; i >= pos + len; i--)

{

_str[i] = _str[i - len];

}

memcpy(_str + pos, s, len);

_size += len;

_str[_size] = '\0';

}

void insert(size_t pos, size_t n, char c)

{

assert(pos >= 0 && pos < _size);

if (_size + n > _capacity)

{

reserve(_size + n);

}

//挪动数据

for (size_t i = _size+n; i >= pos + n; i--)

{

_str[i] = _str[i - n];

}

for (size_t i = 0; i < n; i++)

{

_str[pos + i] = c;

}

_size += n;

_str[_size] = '\0';

}

void erase(size_t pos, size_t len = npos)

{

assert(pos >= 0 && pos < _size);

if (len == npos)

{

_str[0] = '\0';

_size = 0;

return;

}

for (size_t i = pos; (len + i) < _size; i++)

{

_str[i] = _str[i + len];

}

_size -= len;

_str[_size] = '\0';

}

//find

size_t find(const string& str, size_t pos = 0)

{

assert(pos >= 0 && pos < _size);

char* tmp = strstr(_str + pos, str._str);

if (tmp == nullptr)

{

return -1;

}

return tmp - _str;

}

size_t find(const char* s, size_t pos = 0)

{

assert(pos >= 0 && pos < _size);

char* tmp = strstr(_str + pos, s);

if (tmp == nullptr)

{

return -1;

}

return tmp - _str;

}

size_t find(char c, size_t pos = 0)

{

assert(pos >= 0 && pos < _size);

for (size_t i = pos; i < _size; i++)

{

if (_str[i] == c)

{

return i;

}

}

return -1;

}

//swap

void swap(string& str)

{

Swap(_str, str._str);

Swap(_size, str._size);

Swap(_capacity, str._capacity);

}

//c_str

const char* c_str() const

{

return _str;

}

char* c_str()

{

return _str;

}

//substr

string substr(size_t pos = 0, size_t len = npos) const

{

assert(pos >= 0 && pos < _size);

size_t n = 0;

if (len == npos || pos + len > _size)

{

n = _size - pos;

}

else

{

n = len;

}

string ret;

for (size_t i = 0; i < n; i++)

{

ret += _str[pos + i];

}

return ret;

}

//其他成员函数

size_t size() const

{

return _size;

}

size_t length()const

{

return _size;

}

size_t capacity()const

{

return _capacity;

}

void clear()

{

_str[0] = '\0';

_size = 0;

}

bool empty()const

{

return _size == 0;

}

void resize(size_t n)

{

if (n > _capacity)

{

reserve(n);

}

_size = n;

_str[_size] = '\0';

}

void resize(size_t n, char c)

{

if (n > _capacity)

{

reserve(n);

}

for (size_t i = _size; i < n; i++)

{

_str[i] = c;

}

_size = n;

_str[_size] = '\0';

}

private:

char* _str;

size_t _size;

size_t _capacity;

const static size_t npos;

};

const size_t HL::string::npos = -1;

std::ostream& operator<<(std::ostream& out, const HL::string& str)

{

//for (int i = 0; i < str.size(); i++)

//{

//out << str[i];

//}

//return out;

for (auto ch : str)

{

out << ch;

}

return out;

}

std::istream& operator>>(std::istream& in, HL::string& str)

{

char s[128] = { 0 };

char ch;

ch = in.get();

while (ch == ' ' || ch == '\n')

{

ch = in.get();

}

str.clear();

int i = 0;

while (ch != '\n')

{

s[i] = ch;

i++;

if (i == 127)

{

s[i] = '\0';

str += s;

i = 0;

}

ch = in.get();

}

if (i)

{

str += s;

}

return in;

}

};



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。