赞
踩
string类的模拟实现我们定义三个成员变量
- class string
- {
- public:
- //...
- private:
- char* _str;
- size_t _size;
- size_t _capacity;
- };
下面对其中的成员函数进行依次的实现
构造函数分为无参和带参这两种
无参构造函数默认构造空字符串"",所以我们只需要写一个带参的并给一个缺省值即可
- string::string(const char* str)
- :_size(strlen(str))
- {
- _str = new char[_size + 1];
- _capacity = _size;
- strcpy(_str, str);
- }
注意:这里的_str开空间时要加1,是给\0预留位置
对于string类型来说,如果不写拷贝构造会导致浅拷贝问题(只完成值拷贝)
所以我们需要进行深拷贝
这里先介绍一种传统写法,也是比较简单的写法
- string::string(const string& s)
- {
- _str = new char[s._capacity + 1];
- strcpy(_str, s._str);
- _size = s._size;
- _capacity = s._capacity;
- }
在之前学习string的使用时,我们会发现明明std中就有swap,为什么string还要再实现一个?
这是因为第一个swap的交换代价比较大,它会进行深拷贝,造成空间损耗,所以我们在自己实现swap时要考虑到这一点,可以采用交换两者指针的方式:
- void string::swap(string& s)
- {
- std::swap(_str, s._str);
- std::swap(_size, s._size);
- std::swap(_capacity, s._capacity);
- }
默认生成的赋值重载也会导致浅拷贝,所以我们需要实现深拷贝
这里我们也用传统写法,也是比较简单的写法
- string& string::operator=(const string& 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::~string()
- {
- delete[] _str;
- _str = nullptr;
- _size = _capacity = 0;
- }
下面我们来看几个常用的接口实现
- const char* string::c_str() const
- {
- return _str;
- }
- char& string::operator[](size_t pos)//普通对象:可读可写
- {
- assert(pos < _size);
- return _str[pos];
- }
迭代器
- typedef char* iterator;
- string::iterator string::begin()
- {
- return _str;
- }
- string::iterator string::end()
- {
- return _str + _size;
- }
-
- //遍历
- string::iterator it1 = s1.begin();
- while (it1 != s1.end())
- {
- cout << *it1 << " ";
- ++it1;
- }
- cout << endl;
范围for(底层还是迭代器)
- typedef char* iterator;
- string::iterator string::begin()
- {
- return _str;
- }
- string::iterator string::end()
- {
- return _str + _size;
- }
-
- //遍历
- for (auto e: s1)
- {
- cout << e << " ";
- }
- cout << endl;
打印结果如下:
- size_t size() const
- {
- return _size;
- }
开辟新的空间,然后进行拷贝,对旧空间进行释放
-
- 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’要重新处理
- void string::push_back(char ch)
- {
- if (_size == _capacity)
- {
- size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
- reserve(newcapacity);
- }
-
- _str[_size] = ch;
- _str[_size + 1] = '\0';
- ++_size;
-
- }
尾插字符串,这里我们需要计算,然后决定开多少空间(直接开2倍可能不够用)
- void string::append(const char* str)
- {
- size_t len = strlen(str);
- if (_size + len > _capacity)
- {
- reserve(_size + len);
- }
-
- strcpy(_str+_size, str);
- _size += len;
-
- }
这个比较简单,我们可以复用上面的分为+=字符和+=字符串push_back和append
- string& string::operator+=(char ch)//字符
- {
- push_back(ch);
-
- return *this;
- }
-
- string& string::operator+=(const char* str)//字符串
- {
- append(str);
-
- return *this;
- }
insert的代码,我们要注意画图,尤其是关于边界的一些条件的处理,我们要小心
- void string::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 string::insert(size_t pos, const char* str)//处理字符串
- {
- assert(pos <= _size);
-
- size_t len = strlen(str);
- if (_size + len > _capacity)
- {
- reserve(_size + len);
- }
-
- size_t end = _size + len;
- while (end > pos + len - 1)//这里的边界要控制清楚!
- {
- _str[end] = _str[end - len];//右移
- --end;
- }
-
- memcpy(_str + pos, str, len);
- _size += len;
- }
说到erase,自然要跟npos联系起来,npos是string类的静态成员变量
我们可以采用定义和声明分离的方法:
const static size_t npos;//写在string.h中
const size_t string::npos = -1;//写在string.cpp中
下面来实现这个删除功能:
- void string::erase(size_t pos, size_t len)
- {
- assert(pos < _size);
-
- // len大于前面字符个数时,有多少删多少
- if (len >= _size - pos)
- {
- _str[pos] = '\0';
- _size = pos;
- }
-
- else
- {
- strcpy(_str + pos, _str + pos + len);
- _size -= len;
- }
-
- }
从pos处开始查找字符或者字符串,找到返回下标值,没找到则返回npos
- size_t string::find(char ch, size_t pos)//字符
- {
- for (size_t i = pos; i < _size; i++)
- {
- if (_str[i] == ch)
- {
- return i;
- }
- }
-
- return npos;
- }
-
- size_t string::find(const char* sub, size_t pos)//字符串
- {
- char* p = strstr(_str + pos, sub);//调用现成的strstr来实现
- return p - _str;
- }
流插入(输出)和流提取(输入)我们之前在日期类的时候也实现过了,我们知道它不适合写成 成员函数,之前我们用的是友元,这样才能访问私有,但这里我们可以不访问私有,挨个挨个遍历,所以可以这么写:
流插入<<
- ostream& operator<< (ostream& os, const string& str)//流插入(输出)
- {
- for (size_t i = 0; i < str.size(); i++)
- {
- os << str[i];
- }
-
- return os;
- }
流提取>>
- istream& operator>> (istream& is, string& str)//流提取(输入)
- {
- char ch = is.get();
- while (ch != ' ' && ch != '\n')
- {
- str += ch;
- ch = is.get();
- }
-
- return is;
- }
但是这样还不够,我们会发现之前的数据它还留着:
所以我们需要再写个clear()来清理数据:
- void string::clear()
- {
- _str[0] = '\0';
- _size = 0;
- }
-
- istream& operator>> (istream& is, string& str)//流提取(输入)
- {
- str.clear();
- char ch = is.get();
- while (ch != ' ' && ch != '\n')
- {
- str += ch;
- ch = is.get();
- }
-
- return is;
- }
这里模拟实现string类用了 string.h , string.cpp 和 test.cpp 三个文件来实现
这里给出string的各个函数定义和实现的代码
string.h
- #define _CRT_SECURE_NO_WARNINGS 1
- #pragma once
- #include <iostream>
- #include <assert.h>
- #include <string>
- using namespace std;
-
- namespace bit
- {
- class string
- {
- public:
- typedef char* iterator;
- typedef const char* const_iterator;
-
- iterator begin();
- iterator end();
-
- const_iterator begin() const;
- const_iterator end() const;
-
- string(const char* str = "");
- ~string();
- const char* c_str() const;
-
- size_t size() const;
- char& operator[](size_t pos);
- const char& operator[](size_t pos) const;
-
- void push_back(char ch);
- void append(const char* str);
-
-
- void insert(size_t pos, char ch);
- void insert(size_t pos, const char* str);
- void reserve(size_t n);
- string& operator+=(char ch);
- string& operator+=(const char* str);
- void erase(size_t pos = 0, size_t len = npos);
-
- string(const string& s);
- string& operator=(const string& s);
-
- size_t find(char ch, size_t pos = 0);
- size_t find(const char* sub, size_t pos = 0);
-
- void swap(string& s);
- string substr(size_t pos = 0, size_t len = npos);
-
- bool operator<(const string& s) const;
- bool operator>(const string& s) const;
- bool operator<=(const string& s) const;
- bool operator>=(const string& s) const;
- bool operator==(const string& s) const;
- bool operator!=(const string& s) const;
- void clear();
-
-
- private:
- char* _str;
- size_t _size;
- size_t _capacity;
- const static size_t npos;
- };
-
- istream& operator>> (istream& is, string& str);
- ostream& operator<< (ostream& os, const string& str);
-
- }
string.cpp
- #include "string.h"
-
- namespace bit
- {
- const size_t string::npos = -1;
-
- string::iterator string::begin()
- {
- return _str;
- }
-
- string::iterator string::end()
- {
- return _str + _size;
- }
-
- string::const_iterator string::begin() const
- {
- return _str;
- }
-
- string::const_iterator string::end() const
- {
- return _str + _size;
- }
-
-
- string::string(const char* str)
- :_size(strlen(str))
- {
- _str = new char[_size + 1];
- _capacity = _size;
- strcpy(_str, str);
- }
-
- string::string(const string& s)
- {
- _str = new char[s._capacity + 1];
- strcpy(_str, s._str);
- _size = s._size;
- _capacity = s._capacity;
- }
-
-
- string::~string()
- {
- delete[] _str;
- _str = nullptr;
- _size = _capacity = 0;
- }
-
- const char* string::c_str() const
- {
- return _str;
- }
-
- size_t string::size() const
- {
- return _size;
- }
-
- string& 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;
- }
-
- char& string::operator[](size_t pos)
- {
- assert(pos < _size);
- return _str[pos];
- }
-
- const char& string::operator[](size_t pos) const
- {
- assert(pos < _size);
- return _str[pos];
- }
-
- void string::reserve(size_t n)
- {
- if (n > _capacity)
- {
- char* tmp = new char[n + 1];
- strcpy(tmp, _str);
- delete[] _str;
-
- _str = tmp;
- _capacity = n;
- }
- }
-
- void string::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 string::insert(size_t pos, const char* str)
- {
- assert(pos <= _size);
-
- size_t len = strlen(str);
- if (_size + len > _capacity)
- {
- reserve(_size + len);
- }
-
- size_t end = _size + len;
- while (end > pos + len - 1)
- {
- _str[end] = _str[end - len];//右移
- --end;
- }
-
- memcpy(_str + pos, str, len);
- _size += len;
- }
-
- void string::push_back(char ch)
- {
- if (_size == _capacity)
- {
- size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
- reserve(newcapacity);
- }
-
- _str[_size] = ch;
- _str[_size + 1] = '\0';
- ++_size;
-
- }
-
- void string::append(const char* str)
- {
- size_t len = strlen(str);
- if (_size + len > _capacity)
- {
- reserve(_size + len);
- }
-
- strcpy(_str+_size, str);
- _size += len;
-
- }
-
- string& string::operator+=(char ch)
- {
- push_back(ch);
-
- return *this;
- }
-
- string& string::operator+=(const char* str)
- {
- append(str);
-
- return *this;
- }
-
- void string::erase(size_t pos, size_t len)
- {
- assert(pos < _size);
-
- // len大于前面字符个数时,有多少删多少
- if (len >= _size - pos)
- {
- _str[pos] = '\0';
- _size = pos;
- }
-
- else
- {
- strcpy(_str + pos, _str + pos + len);
- _size -= len;
- }
-
- }
-
- size_t string::find(char ch, size_t pos)
- {
- for (size_t i = pos; i < _size; i++)
- {
- if (_str[i] == ch)
- {
- return i;
- }
- }
-
- return npos;
- }
-
- size_t string::find(const char* sub, size_t pos)
- {
- char* p = strstr(_str + pos, sub);
- return p - _str;
- }
-
- void string::swap(string& s)
- {
- std::swap(_str, s._str);
- std::swap(_size, s._size);
- std::swap(_capacity, s._capacity);
- }
-
- string string::substr(size_t pos, size_t len)
- {
- // len大于后面剩余字符,有多少取多少
- if (len > _size - pos)
- {
- string sub(_str + pos);//直接构造子串返回
- return sub;
- }
-
- //len <= _size - pos
- else
- {
- string sub;
- sub.reserve(len);
- for (size_t i = 0; i < len; i++)
- {
- sub += _str[pos + i];
- }
-
- return sub;
- }
- }
-
-
- bool string::operator<(const string& s) const
- {
- return strcmp(_str, s._str) < 0;
- }
-
- bool string::operator>(const string& s) const
- {
- return !(*this <= s);
- }
-
- bool string::operator<=(const string& s) const
- {
- return *this < s || *this == s;
- }
-
- bool string::operator>=(const string& s) const
- {
- return !(*this < s);
- }
-
- bool string::operator==(const string& s) const
- {
- return strcmp(_str, s._str) == 0;
- }
-
- bool string::operator!=(const string& s) const
- {
- return !(*this == s);
- }
-
- void string::clear()
- {
- _str[0] = '\0';
- _size = 0;
- }
-
-
- istream& operator>> (istream& is, string& str)
- {
- str.clear();
- char ch = is.get();
- while (ch != ' ' && ch != '\n')
- {
- str += ch;
- ch = is.get();
- }
-
- return is;
- }
-
- ostream& operator<< (ostream& os, const string& str)
- {
- for (size_t i = 0; i < str.size(); i++)
- {
- os << str[i];
- }
-
- return os;
- }
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。