这篇文章,主要就是展示模拟实现C++标准库中的string类的代码,下面就是具体的代码,同时也上传了具体的文件。
string.h(头文件)
// string.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#include <assert.h>
namespace Alen
{
class string
{
// 类里面定义的成员函数默认是内敛函数,内敛不会放在符号表所以不会链接错误
public:
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;
}
string(const char* str = "")
{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
// 深拷贝问题
// 写法一:老写法
/*
string(const string& s)
{
_str = new char[s._capacity + 1];
strcpy(_str, s._str);
_size = s._size;
_capacity = s._capacity;
}
*/
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
// 方法二:
string(const string& s)
{
string tmp(s._str);
swap(tmp);
}
//string& operator=(const string& s)
//{
// if (this != &s)
// {
// /*delete[] _str;
// _str = new char[s._capacity + 1];
// strcpy(_str, s._str);
// _size = s._size;
// _capacity = s._capacity;*/
// //string tmp(s._str);
// string tmp(s);
// swap(tmp);
//
// }
// return *this;
//}
string& operator=(string tmp)
{
swap(tmp);
return *this;
}
~string()
{
if (_str)
{
delete[] _str; // delete中对nullptr特别处理了,也可以不需要手动判断
_str = nullptr;
_size = _capacity = 0;
}
}
const char* c_str() const
{
return _str;
}
void reserve(size_t newCapacity);
void clear();
void push_back(char c);
string& operator+=(char c);
void append(const char* s);
string& operator+=(const char* s);
void insert(size_t pos, char ch);
void insert(size_t pos, const char* s);
void erase(size_t pos, size_t len = npos);
size_t find(char c, size_t pos = 0);
size_t find(const char* s, size_t pos = 0);
string substr(size_t pos = 0, size_t len = npos);
private:
char* _str = nullptr;
size_t _capacity;
size_t _size;
static const size_t npos;
};
bool operator<(const string& s1, const string& s2);
bool operator<=(const string& s1, const string& s2);
bool operator>(const string& s1, const string& s2);
bool operator>=(const string& s1, const string& s2);
bool operator==(const string& s1, const string& s2);
bool operator!=(const string& s1, const string& s2);
// 加不加const取决于读还是写
ostream& operator<<(ostream& out, const string& s);
istream& operator>>(istream& in, string& s);
istream& getline(istream& in, string& s, char delim = '\n');
}
string.cpp
// string.cpp
#include "string.h"
namespace Alen
{
const size_t string::npos = -1;
void string::reserve(size_t newCapacity)
{
if (newCapacity > _capacity)
{
char* tmp = new char[newCapacity + 1]; // 多一个空间存'\0'
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = newCapacity;
}
}
void string::clear()
{
_str[0] = '\0';
_size = 0;
}
void string::push_back(char c)
{
if (_size == _capacity)
reserve(_capacity == 0 ? 4 : _capacity * 2); // 进行2倍扩容
_str[_size++] = c;
_str[_size] = '\0'; // !!!
}
string& string::operator+=(char c)
{
push_back(c);
return *this;
}
void string::append(const char* s)
{
size_t len = strlen(s);
if (_size + len > _capacity)
{
reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);
}
strcpy(_str + _size, s);
_size += len;
}
string& string::operator+=(const char* s)
{
append(s);
return *this;
}
void string::insert(size_t pos, char ch)
{
assert(pos <= _size);
if (_size == _capacity)
reserve(_capacity == 0 ? 4 : _capacity * 2);
// 挪动数据
// end 是int类型,pos是size_t类型,比较会将end隐式类型转换成size_t
// 当end为-1的(即pos为0)时候,就成为了size_t的最大值
//int end = _size;
//while (end >= pos)
//{
// _str[end + 1] = _str[end];
// --end;
//}
//_str[pos] = ch;
//++_size;
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* s)
{
assert(pos <= _size);
size_t len = strlen(s);
if (_size + len > _capacity)
reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
// 挪动数据
size_t end = _size + len;
while (end > pos + len - 1)
{
_str[end] = _str[end - len];
}
for (size_t i = 0; i < len; i++)
{
_str[pos + i] = s[i];
}
}
void string::erase(size_t pos, size_t len)
{
assert(pos < _size);
if (len >= _size - pos)
{
_str[pos] = '\0';
_size = pos;
}
else
{
for (size_t i = pos + len; i <= _size; i++)
{
_str[i - len] = _str[i];
}
_size -= len;
}
}
size_t string::find(char c, size_t pos)
{
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == c)
{
return i;
}
}
return npos;
}
// 可以使用KMP、BM算法
size_t string::find(const char* s, size_t pos)
{
assert(pos < _size);
const char* ptr = strstr(_str + pos, s);
if (ptr == nullptr)
{
return npos;
}
else
{
return ptr - _str;
}
}
string string::substr(size_t pos, size_t len)
{
assert(pos < _size);
if (len > _size - pos)
{
len = _size - pos;
}
string sub;
sub.reserve(len);
for (size_t i = 0; i < len; i++)
{
sub += _str[pos + i];
}
return sub;
}
bool operator<(const string& s1, const string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) < 0;
}
bool operator<=(const string& s1, const string& s2)
{
return s1 < s2 || s1 == s2;
}
bool operator>(const string& s1, const string& s2)
{
return !(s1 <= s2);
}
bool operator>=(const string& s1, const string& s2)
{
return !(s1 < s2);
}
bool operator==(const string& s1, const string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) == 0;
}
bool operator!=(const string& s1, const string& s2)
{
return !(s1 == s2);
}
ostream& operator<<(ostream& out, const string& s)
{
for (auto ch : s)
{
out << ch;
}
return out;
}
void IN(istream& in ,string& s, char option = '\n')
{
char ch;
const int N = 256;
char buff[N]; // 利用缓存区的思路,来减少string的扩容操作,增加效率
int i = 0;
ch = in.get(); // = C语言的getc一个字符一个字符读
while (option == ' ' ? ch != ' ' && ch != '\n' : ch != option)
{
buff[i++] = ch;
if (i == N - 1)
{
buff[i] = '\0';
s += buff;
i = 0;
}
//s += ch;
ch = in.get();
}
if (i > 0)
{
buff[i] = '\0';
s += buff;
}
}
istream& operator>>(istream& in, string& s)
{
s.clear();
/*
char ch;
//in >> ch; // 将 ' ' 与 '\n'作为分隔符,直接忽视不会读取
//while (ch != ' ' && ch != '\n')
//{
// s += ch;
// in >> ch;
//}
const int N = 256;
char buff[N]; // 利用缓存区的思路,来减少string的扩容操作,增加效率
int i = 0;
ch = in.get(); // = C语言的getc一个字符一个字符读
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == N - 1)
{
buff[i] = '\0';
s += buff;
i = 0;
}
//s += ch;
ch = in.get();
}
if (i > 0)
{
buff[i] = '\0';
s += buff;
}
*/
IN(in, s, ' ');
return in;
}
istream& getline(istream& in, string& s, char delim)
{
s.clear();
IN(in, s, delim);
return in;
}
}
Test.cpp(测试文件 / 主函数)
// Test.cpp
#include "string.h"
namespace Alen
{
void teststring1()
{
string s("hello world");
s += 's';
s += "abc";
for (auto& ch : s)
{
ch += 1;
}
cout << s.c_str() << endl;
}
void teststring2()
{
string s("hello world");
s.erase(6, 3);
cout << s.c_str() << endl;
}
void teststring3()
{
string s("test.cpp.zip");
size_t pos1 = s.find('.');
size_t pos2 = s.find("cpp");
string suffix1 = s.substr(pos1);
string suffix2 = s.substr(pos2);
cout << suffix1.c_str() << endl;
cout << suffix2.c_str() << endl;
}
void teststring4()
{
string s1("hello world");
string s2("hello world");
cout << (s1 < s2) << endl;
cout << (s1 == s2) << endl;
cout << ("hello world" < s2) << endl;
cout << (s1 == "hello world") << endl; // 将 "hello world"隐式类型转换成string临时对象
cout << ("hello world" == "hello world") << endl; // 两个指针的比较(运算符重载必须有一个对应的对象识别)
}
void teststring5()
{
string s("hello world");
string s1 = s;
getline(cin, s);
getline(cin, s, '*');
cout << s << endl;
}
}
int main()
{
//Alen::teststring5();
return 0;
}