#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace zh
{
class string
{
public:
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
//构造函数
string(const char* str = "")
:_size(strlen(str)), _capacity(_size)
{
_str = new char[_capacity + 1];
strcpy(_str, str);
}
//拷贝构造
string(const string& s)
//必须将_str初始化为nullptr
//因为tmp析构的时候如果_str是随机地址的话会出现问题
:_str(nullptr), _size(0), _capacity(0)
{
string tmp(s._str);
swap(tmp);
/*std::swap(_str, tmp._str);
std::swap(_size, tmp._size);
std::swap(_capacity, tmp._capacity);*/
}
//赋值重载
string& operator= (string s)
{
//可以使用自己在string类中定义的swap,从而减少代码的冗余
//第二个原因是因为在使用的时候,自己写的swap效率更高,
//因为都是对成员变量的交换。
//而如果使用std中的swap,它是一个模板,交换会涉及深拷贝,代价大。
swap(s);
//也可以直接用模板中的swap
/*std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);*/
return *this;
}
//析构函数
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
//返回有效字符的多少
//为什么加一个const?
//因为这样不管是const属性对象还是非const属性对象,都可以使用该函数
size_t size() const
{
return _size;
}
//返回容量
size_t capacity() const
{
return _capacity;
}
//返回c语言字符串形式
const char* c_str() const
{
return _str;
}
//对[]的重载
char& operator[] (size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[] (size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
//正向迭代器,以及const属性的正向迭代器
typedef char* iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
typedef const char* const_iterator;
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
//增容函数
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
void resize(size_t n, char ch = '\0')
{
if (n < _size)
{
_size = n;
_str[n] = '\0';
}
else
{
if (n > _capacity)
{
reserve(n);
}
for (size_t i = _size; i < n; ++i)
{
_str[i] = ch;
}
_size = n;
_str[_size] = '\0';
}
}
//尾插
void push_back(char ch)
{
//考虑扩容
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : 2 * _capacity);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
//insert(_size, ch);
}
void append(const char* str)
{
//考虑是否要扩容,不能直接扩二倍,可能要插入的字符串会比二倍大
int slen = strlen(str);
if (_size + slen > _capacity)
{
reserve(_size + slen + 1);
}
strcpy(_str + _size, str);
_size += slen;
//insert(_size, str);
}
//重载+=
string& operator+= (char ch)
{
push_back(ch);
return *this;
}
string& operator+= (const char* str)
{
append(str);
return *this;
}
//查找一个字符
size_t find(char ch)
{
for (size_t i = 0; i < _size; ++i)
{
if (_str[i] == ch)
{
return i;
}
}
return npos;
}
//查找一个字符串
size_t find(const char* s, size_t pos = 0)
{
//strstr是查找字符串的函数
char* tmp = strstr(_str + pos, s);
if (tmp == nullptr)
{
return npos;
}
else
{
//直接指针相减就是元素个数
return tmp - _str;
}
}
//在pos位置去插入一个字符
string& insert(size_t pos, char ch)
{
assert(pos <= _size);
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : 2 * _capacity);
}
//这里会有bug,因为end是无符号数,当pos=0的时候,
//end会变成-1的形式,从而变成一个很大的正数,从而死循环。
//就算是把end设置成int也不行,因为在和pos作比较的时候,end会发生提升从而变成无符号数
/*size_t end = _size;
while (end >= pos)
{
_str[end + 1] = _str[end];
--end;
}*/
//那怎么实现呢?
//(1)我们把end指向_size + 1;
//这样就不会出现问题
size_t end = _size + 1;
while (end > pos)
{
_str[end] = _str[end - 1];
--end;
}
_str[pos] = ch;
++_size;
return *this;
//
}
//在pos位置去插入一个字符串
string& insert(size_t pos, const char* s)
{
//先扩容
assert(pos <= _size);
size_t slen = strlen(s);
if (slen + _size > _capacity)
{
reserve(slen + _size);
}
size_t end = _size + slen;
while (end >= pos + slen )
{
_str[end] = _str[end - slen];
--end;
}
for (size_t i = 0; i < slen; ++i)
{
_str[pos + i] = s[i];
}
_size += slen;
return *this;
}
//从pos开始,删除len个字符,如果len 很大,全部删除就行了
string& erase(size_t pos = 0, size_t len = npos)
{
assert(pos < _size);
if (len = npos || pos + len >= _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
}
//清理string
void clear()
{
_str[0] = '\0';
_size = 0;
}
private:
char* _str;
size_t _size;//已经有多少个有限字符
size_t _capacity;//最大可以存多少个有效字符
static const size_t npos;
};
const size_t string::npos = -1;
//重载> < 等,重载成全局的
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 strcmp(s1.c_str(), s2.c_str()) > 0 ;
}
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 strcmp(s1.c_str(), s2.c_str()) >= 0;
}
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 strcmp(s1.c_str(), s1.c_str()) != 0;
}
//<<z可以自动识别类型,
ostream& operator<< (ostream& out, const string& s)
{
for (size_t i = 0; i < s.size(); ++i)
{
out << s[i];
}
//不用使用这个方法,不符合规范
//例如string s = "hello";
//s += '\0';
//s += "world";
//cout << s << endl;打印的结果应该是hello world
//out << s.c_str();//这样写的话只打印hello
return out;
}
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch = in.get();
while (ch != ' ' && ch != '\n')
{
s += ch;
ch = in.get();
}
return in;
}
//void TestString1()
//{
// string s("hello world");
// //迭代器
// /*string::iterator it = s.begin();
// while (it != s.end())
// {
// cout << *it << " ";
// it++;
// }
// cout << endl;*/
// //范围for,语法糖
// /*for (auto e : s)
// {
// cout << e << " ";
// }*/
// //重载[]
// for (size_t i = 0; i < s.size(); ++i)
// {
// cout << s[i] << " ";
// }
//}
//void TestString2()
//{
// zh::string s = "hello world";
// s.push_back('!');
// s.append("yyds");
// cout << (s.c_str()) << endl;
//
// string s2;
// s2 += 'z';
// s2 += "hyyds yyds";
// cout << (s2.c_str()) << endl;
//}
//void TestString3()
//{
// /*string s = "abcdefg";
// s.resize(100, 'x');
// cout << s.c_str() << endl;*/
// string s = "hell";
// string s1 = "hello";
// if (s > s1)
// {
// cout << 1 << endl;
// }
// else
// {
// cout << 2 << endl;
// }
//}
void TestString4()
{
string s = "hello";
s += '\0';
s += "world";
cout << s << endl;
cin >> s;
cout << s << endl;
}
};
C++string的模拟实现
最新推荐文章于 2024-10-16 10:13:45 发布
这篇博客详细介绍了如何实现一个自定义的字符串类,包括构造函数、拷贝构造、赋值重载、迭代器、内存管理如resize、reserve等方法。此外,还涵盖了字符串的查找、插入、删除等操作,以及与C++标准库中的iostream进行交互。
摘要由CSDN通过智能技术生成