因为在自己写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类中的swapvoid 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;}
}