因为在自己写string类的时候没有涉及到模板,所以就分成两个文件去实现。(由于太多,这里只挑选常用的接口)
string.h
#pragma once
#include<iostream>
#include<string>
#include<assert.h>
using namespace std;
namespace hebre
{
class string
{
public:
using iterator = char*;
using const_iterator = const char*;
string();
string(const char* c);
string(const string& c);
//string& operator=(const string& str);
string& operator=(string str);
string& operator+=(char ch);
string& operator+=(const char* c);
~string();
void push_back(char ch);
void append(const char* c);
void reserve(size_t n);
void insert(size_t pos, size_t n, char ch);
void insert(size_t pos, const char* c);
void erase(size_t pos, size_t len = npos);
void clear();
void swap(string& str);
size_t find(char ch, size_t pos = 0);
size_t find(const char* c, size_t pos = 0);
string substr(size_t pos, size_t len = npos);
char& operator[](size_t i)
{
assert(i < _size);
return _str[i];
}
const char& operator[](size_t i) const
{
assert(i < _size);
return _str[i];
}
size_t size() const
{
return _size;
}
size_t capacity() const
{
return _capacity;
}
const char* c_str() const
{
return _str;
}
iterator begin()
{
return _str;
}
const_iterator begin() const
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator end() const
{
return _str + _size;
}
private:
char* _str;
size_t _size;
size_t _capacity;
public:
static size_t npos;
};
void swap(string& s1, string& s2);
bool operator== (const string& lhs, const string& rhs);
bool operator!= (const string& lhs, const string& rhs);
bool operator> (const string& lhs, const string& rhs);
bool operator< (const string& lhs, const string& rhs);
bool operator>= (const string& lhs, const string& rhs);
bool operator<= (const string& lhs, const string& rhs);
ostream& operator<<(ostream& os, const string& str);
istream& operator>>(istream& is, string& str);
istream& getline(istream& is, string& str, char delim = '\n');
}
string.cpp
#include"string.h"
namespace hebre
{
//要在.cpp文件里定义静态成员变量
//如果在.h文件里定义的话,npos在string.cpp和test.cpp文件在生成可执行文件都会重新再次定义一遍
size_t string:: npos = -1;
string::string()
:_str(new char[1] {'\0'})
, _size(0)
, _capacity(0)
{}
string::string(const char* c)
:_size(strlen(c))
{
_str = new char[_size + 1];
_capacity = _size;
strcpy(_str, c);
}
//传统写法
//string::string(const string& c)
// :_size(c._size)
//{
// _str = new char[_size + 1];
// _capacity = c._capacity;
// strcpy(_str, c._str);
//}
string::string(const string& c)
{
string tmp(c._str);
swap(tmp);
}
//s1=s2
//传统写法
//string& string::operator=(const string& str)
//{
// if (this != &str)//避免自己赋值给自己
// {
// delete[]_str;
// _str = new char[(str._capacity + 1)];
// strcpy(_str, str._str);
// _size = str._size;
// _capacity = str._capacity;
// }
// return *this;
//}
string& string::operator=(string str)
{
swap(str);
return *this;
}
string& string::operator+=(char ch)
{
push_back(ch);
return *this;
}
string& string::operator+=(const char* c)
{
append(c);
return *this;
}
void string::insert(size_t pos, size_t n, char ch)//n代表ch的个数
{
assert(pos <= _size);
if (_capacity < _size + n)
{
size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
if (newcapacity < _size + n)
{
newcapacity = _size + n + 1;
}
reserve(newcapacity);
}
size_t end = _size+n;
while (end>=pos+n)
{
_str[end] = _str[end - n];
end--;
}
size_t num = n, i = pos;
while (num)
{
_str[i] = ch;
i++;
num--;
}
_size += n;
}
void string::insert(size_t pos, const char* c)
{
assert(pos <= _size);
size_t n = strlen(c);
if (_capacity < _size + n)
{
size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
if (newcapacity < _size + n)
{
newcapacity = _size + n + 1;
}
reserve(newcapacity);
}
size_t end = _size + n;
while (end >= pos + n)
{
_str[end] = _str[end - n];
end--;
}
for (int i = 0; i < n; i++)
{
_str[pos+i] = c[i];
}
_size += n;
}
void string::erase(size_t pos, size_t len)
{
assert(pos <= _size);
if (len >= _size - pos)
{
_str[pos] = '\0';
}
else
{
size_t cur = pos + len;
while (cur <= _size)
{
_str[cur - len] = _str[cur];
cur++;
}
}
}
void string::clear()
{
_str[0] = '\0';
_size = 0;
}
size_t string::find(char ch, size_t pos)
{
assert(pos < _size);
size_t cur = pos;
while (cur < _size)
{
if (_str[cur] == ch)
{
return cur;
}
cur++;
}
return npos;
}
size_t string::find(const char* c, size_t pos)
{
assert(pos < _size);
size_t cur = pos;
size_t len = strlen(c);
char* check = strstr(_str, c);//检查是否含有子串的函数
if (check != nullptr)
{
return _str - check;
}
return npos;
}
string string::substr(size_t pos, size_t len)
{
assert(pos < _size);
if (len > _size - pos)
{
len = _size - pos;
}
hebre::string sub;
sub.reserve(len);
for(int i = 0; i < len; i++)
{
sub += _str[pos + i];
}
return sub;
}
string::~string()
{
delete[] _str;
_str = nullptr;
_size = 0;
_capacity = 0;
}
void string::push_back(char ch)
{
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : 2 * _capacity);
}
_str[_size] = ch;
_str[_size + 1] = '\0';
_size++;
}
void string::append(const char* c)
{
if ((_size + strlen(c) > _capacity))
{
size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;
if (_size + strlen(c) > newcapacity)
{
newcapacity = _size + strlen(c) + 1;
}
reserve(newcapacity);
}
strcpy(_str + _size, c);
_str[_size + strlen(c)] = '\0';
_size += strlen(c);
}
void string::reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[]_str;
_str = tmp;
_capacity = n;
}
}
//在std中的swap若交换的是自定义类型,会经历很多的拷贝和析构,效率较低
//我们自己实现的swap直接将其地址交换就可以取代很多不必要的操作
void string::swap(string& str)
{
std::swap(_str, str._str);
std::swap(_size, str._size);
std::swap(_capacity, str._capacity);
}
/
//直接复用hebre::string类中的swap
void swap(string& s1, string& s2)
{
s1.swap(s2);
}
bool operator== (const string& lhs, const string& rhs)
{
return strcmp(lhs.c_str(), rhs.c_str()) == 0;
}
bool operator!= (const string& lhs, const string& rhs)
{
return !(lhs == rhs);
}
bool operator> (const string& lhs, const string& rhs)
{
return !(lhs <= rhs);
}
bool operator< (const string& lhs, const string& rhs)
{
return strcmp(lhs.c_str(), rhs.c_str()) < 0;
}
bool operator>= (const string& lhs, const string& rhs)
{
return !(lhs < rhs);
}
bool operator<= (const string& lhs, const string& rhs)
{
return lhs < rhs || lhs == rhs;
}
ostream& operator<<(ostream& os, const string& str)
{
hebre::string::const_iterator it = str.begin();
while (it != str.end())
{
os << *it;
it++;
}
return os;
}
istream& operator>>(istream& is, string& str)
{
str.clear();
char ch;
//这里我们不可以直接使用>>去获取字符
//无论在cin还是scanf当中,默认换行和空格就是多个字符的分割
//所以遇到换行和空格就会自动刷新缓存区
//在这里的in>>,它会自动忽略掉换行和空格,所以就获取不到换行和空格
//is >> ch;
//get()同样也是istream库里的一个函数,它可以获取所有字符
char buff[256];
//使用buff减少扩容
//同时,由于栈上开空间是在调用main函数的时候直接计算好的
//这就要比在堆上面申请空间是要快上很多
int i = 0;
ch = is.get();
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 255)
{
buff[255] = '\0';
str += buff;
i = 0;
}
ch = is.get();
}
if (i != 0)
{
buff[i] = '\0';
str += buff;
}
return is;
}
istream& getline(istream& is, string& str, char delim)
{
str.clear();
char ch;
char buff[256];//使用buff减少扩容
int i = 0;
ch = is.get();
while (ch != delim)
{
buff[i++] = ch;
if (i == 255)
{
buff[255] = '\0';
str += buff;
i = 0;
}
ch = is.get();
}
if (i != 0)
{
buff[i] = '\0';
str += buff;
}
return is;
}
}