一、基本思路
新建一个项目,在项目中创建头文件string.h 源文件string.cpp
在头文件中,先定义一个新的命名空间(为了防止与库中的string发生冲突),命名空间的名字可以按照自己意愿来命名。
接下来就可以在命名空间中来模拟实现string类辣
在实现的过程中可以多查查string::operator+= - C++ Reference (cplusplus.com)
了解函数功能,然后再去实现
【1】确定成员变量: size_t _size; size_t _capacity; char* _str;
【2】成员函数模拟实现
(1)构造和析构函数
string(const char* str = "")
{
_size = strlen(str);
_capacity = _size;
_str = new char[_size + 1];
my_strcpy(_str, str);//完成初始化工作
}
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
std::cout << "~string()" << std::endl;
}
(2)size()和capacity()
size_t size()const
{
return _size;
}
size_t capacity()const
{
return _capacity;
}
(3)operator[ ]重载
char& operator[](size_t pos)
{
assert(pos <= _size);
return _str[pos];
}
(4)reserve()
void reserve(size_t n = 0)
{
char* tmp = new char[n];//在堆区开辟空间,出函数不会销毁
my_strcpy(tmp, _str);//由于有的vs使用strcpy会报错,所以可以用自己实现的strcpy
delete[] _str;
_str = tmp;
_capacity = n;
}
(5)push_back()
void push_back(char c)
{
if (_size == _capacity)
{
reserve(_capacity == 0 ? 6 : _capacity * 2);
}
_str[_size] = c;
_size++;
_str[_size] = '\0';
}
(6)operator+=的实现
string& operator+= (char c)
{
push_back(c);
return *this;
}
string& operator+= (const char* s)
{
size_t len = strlen(s);
if (_size + len > _capacity)
{
reserve(_size + len+10);
}
append(s);
return *this;
}
(7)append()
string& append(const char* s)
{
size_t len = strlen(s);
if (_size + len > _capacity)
{
reserve(_size + len + 10);
}
my_strcpy(_str + _size, s);
return *this;
}
(8)c_str()
const char* c_str()const
{
return _str;
}
(9)operator<<
这个函数得在类外实现,因为在类内实现的话,默认第一个参数是this,那么在实际使用的时候对象名就得写在ostream的左边,与我们常规写法不一样。
由于库中的_str是私有成员,因此可以通过调用函数c_str来获取_str
std::ostream& operator<<(std::ostream& os, const abl::string& str)
{
os << str.c_str() ;
return os;
}
(10)拷贝构造
//现代写法
string(const string& s)
:_str(nullptr)
,_size(0)
,_capacity(0)
{
string tmp(s._str);//调用默认构造函数string(const char* str = "")
swap(tmp);//this可能没有初始化,析构的时候就会报错,因此要写参数初始化列表
}
//string(const string& s)
//{
// _str = new char[s._capacity + 1];
// memcpy(_str, s._str, s._size);
// _size = s._size;
// _capacity = s._capacity;
//}
(11)insert
string& insert(size_t pos, size_t n, char c)
{
assert(pos <= _size);
if (_size + n > _capacity)
{
reserve(_size + n);
}
size_t end = _size+n;
for (; end>=pos+n; end--)
{
//abcd size==4 pp n==2 end==6 end-n==4
_str[end] = _str[end-n];
}
for (size_t i = 0; i < n; i++)
{
_str[pos + i] = c;
}
_size += n;
return *this;
}
string& insert(size_t pos, const char* s, size_t n)
{
assert(pos <= _size);
size_t len = strlen(s);
if (_size + n > _capacity)
{
reserve(_size + n);
}
size_t end = _size + n;
for (; end >= pos + n; end--)//当pos==0时,end>=pos恒成立,因为end为size_t类型,不可能是负数
{
//abcd size==4 pp n==2 end==6 end-n==4
_str[end] = _str[end - n];
}
for (size_t i = 0; i < n; i++)
{
_str[pos + i] = s[i];
}
_size += n;
return *this;
}
二、完整代码
1、string.h
#pragma once
#include <assert.h>
#include <cstring>
#include <iostream>
#include <stdio.h>
//#include<string.h>
void my_strcpy(char* dest, const char* src) {
while (*src != '\0') {
*dest++ = *src++;
}
*dest = *src; //拷贝\0
}
namespace abl
{
class string
{
//这里暂时还用不到友元,因为在operator>>中并没有访问string的私有成员
//friend std::istream& operator>>(std::istream& in, string& s);
private:
size_t _size;
size_t _capacity;
char* _str;
static size_t npos;
public:
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;//指向首元素
}
iterator end()
{
return _str + _size;//指向'\0'
}
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[_size + 1];
memcpy(_str, str,_size+1);//完成初始化工作
}
~string()
{
//std::cout <<"::"<< _str << std::endl;
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
std::cout << "~string()" << std::endl;
}
//现代写法
string(const string& s)
:_str(nullptr)
,_size(0)
,_capacity(0)
{
string tmp(s._str);//调用默认构造函数string(const char* str = "")
swap(tmp);//this可能没有初始化,析构的时候就会报错,因此要写参数初始化列表
}
//string(const string& s)
//{
// _str = new char[s._capacity + 1];
// memcpy(_str, s._str, s._size);
// _size = s._size;
// _capacity = s._capacity;
//}
void swap(string& tmp)
{
std::swap(_str, tmp._str);
std::swap(_size, tmp._size);
std::swap(_capacity, tmp._capacity);
}
//现代写法
string& operator= (string& s)
{
if (this != &s)
{
string tmp(s);//调用拷贝构造(深拷贝)
swap(tmp);
}
return *this;
}
size_t size()const
{
return _size;
}
size_t capacity()const
{
return _capacity;
}
char& operator[](size_t pos)
{
assert(pos <= _size);
return _str[pos];
}
void reserve(size_t n = 0)
{
//多留出一个空位给\0
char* tmp = new char[n+1];//在堆区开辟空间,出函数不会销毁
my_strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
//只改变了capacity,没有改变size,size不变
}
void push_back(char c)
{
if (_size == _capacity)
{
reserve(_capacity == 0 ? 6 : _capacity * 2);
}
_str[_size] = c;
_size++;
_str[_size] = '\0';
}
string& operator+= (char c)
{
push_back(c);
return *this;
}
string& operator+= (const char* s)
{
size_t len = strlen(s);
if (_size + len > _capacity)
{
reserve(_size + len+10);
}
append(s);
return *this;
}
string& append(const char* s)
{
size_t len = strlen(s);
if (_size + len > _capacity)
{
reserve(_size + len + 1);
}
memcpy(_str + _size, s,len+1);
_size += len;
return *this;
}
string& insert(size_t pos, size_t n, char c)
{
assert(pos <= _size);
if (_size + n > _capacity)
{
reserve(_size + n);
}
size_t end = _size+n;
for (; end>=pos+n; end--)
{
//abcd size==4 pp n==2 end==6 end-n==4
_str[end] = _str[end-n];
}
for (size_t i = 0; i < n; i++)
{
_str[pos + i] = c;
}
_size += n;
return *this;
}
string& insert(size_t pos, const char* s, size_t n)
{
assert(pos <= _size);
size_t len = strlen(s);
if (_size + n > _capacity)
{
reserve(_size + n);
}
size_t end = _size + n;
for (; end >= pos + n; end--)//当pos==0时,end>=pos恒成立,因为end为size_t类型,不可能是负数
{
//abcd size==4 pp n==2 end==6 end-n==4
_str[end] = _str[end - n];
}
for (size_t i = 0; i < n; i++)
{
_str[pos + i] = s[i];
}
_size += n;
return *this;
}
//string& erase(size_t pos = 0, size_t len = npos)
//{
//}
bool operator<(string& s)const
{
size_t i1 = 0, i2 = 0;//遍历两个字符串4
while (i1 < _size && i2 < s._size)
{
if (_str[i1] < s._str[i2])
{
return true;
}
else if (_str[i1] > s._str[i2])
{
return false;
}
else
{
i1++;
i2++;
}
}
//若循环正常进行结束,可能出现的情况:
//hello hello return false
//hellowwww hello return false
//hello hellowww return true
if (_size < s._size)
{
return true;
}
return false;
}
bool operator==(string& s)const
{
//std::cout << s._size << std::endl;
if (_size != s._size)
{
return false;
}
return memcmp(_str, s._str, _size) == 0;
}
bool operator>(string& s)const
{
return !((*this < s) || (*this == s));
}
bool operator<=(string& s)const
{
return !(*this > s);
}
bool operator>=(string& s)const
{
return !(*this < s);
}
//string& operator= (const string& s)
//{
// //开辟新空间,进行拷贝
// if (this != &s)//如果两个对象不相同
// {
// char* tmp = new char[s._capacity + 1];
// memcpy(tmp, s._str, s._size);
// delete[] _str;
// _str = tmp;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
//}
//void swap(string& str)
//{
//
//}
//template<class T>
//void swap(T m)
//{
// T tmp = m;
// m = *this;
// *this = tmp;
//}
const char* c_str()const
{
return _str;
}
void clear()
{
_str[0] = '\0';
_size = 0;
}
};
}
//std::ostream& operator<<(std::ostream& os, const abl::string& str)
//{
// os << str._str << std::endl;
// return os;
//}
size_t abl::string::npos = -1;//静态成员变量必须初始化,并且只能在类体外进行初始化
std::ostream& operator<<(std::ostream& out,const abl::string& str)
{
for (auto ch : str)
{
out << ch;
}
//out << str.c_str();
return out;
}
std::istream& operator>>(std::istream& in, abl::string& s)
{
s.clear();
char bucket[128];//相当于一个桶,装满了再往s里边加,减少了开辟空间的次数,充分利用空间
char c=in.get();
int i = 0;
while (c != ' ' && c != '\n')
{
bucket[i] = c;
i++;
if (i == 127)
{
bucket[i] = '\0';//operator+=中要计算bucket的长度,以'\0'为终止条件,因此要在最后加上
s += bucket;
i = 0;//重新往buckt里边放入数据
}
c = in.get();
}
if (i != 0)
{
bucket[i] = '\0';//...
s += bucket;
}
return in;
}
2、string.cpp
#include <iostream>
#include <cstring>
#include "String.h"
using namespace std;
void test_string1()
{
abl::string s1("hello world");
abl::string s2("legacy.cplusplus.com");
string s3("jdksanxkdsd");
string s4;
cout << s3.c_str() << endl;
cout << s4.c_str() << endl;
cout << s1.c_str() << endl;
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
cout << s2.c_str() << endl;
abl::string::iterator it = s2.begin();
while(it!=s2.end())
{
cout << *it << " ";
++it;
}
cout << endl;
cout << s2 << endl;
}
void test_string2()
{
//string s1("hello");
//cout << s1 << endl;
//cout << s1.capacity() << endl;
//abl::string s2("world");
cout << s2.capacity() << endl;
//s2.push_back('c');
//s2.push_back('c');
//s2.push_back('c');
//cout << s2 << endl;
//s2 += 's';
//cout << s2 << endl;
//s2 += "good";
//cout << s2 << endl;
abl::string s3("hello");
s3.append(" judy");
cout << s3 << endl;
//abl::string s4("helloooo");
s4 += '\0';
//cout << s4 << endl;
//s4 += "wwwwwww";
//s4.insert(2, 3, 'y');
//cout << s4 << endl;
//abl::string s5("hello");
//s5.insert(2, 5, 'p');
//cout << s5 << endl;
//s5.insert(9, "world", 6);
//cout << s5 << endl;
//for (auto ch : s5)
//{
// cout << ch;
//}
//cout << endl;
//string s6;
//cin >> s6;
//cout << s6 << endl;
//cin >> s6;
//cout << s6;
/* cout << s4.npos << endl;*/
}
void test_string3()
{
abl::string s1("hello");
abl::string s2("helloxxxxx");
//cout << (s2 < s1) << endl;
abl::string s3("hello");
//cout << (s1 == s2) << endl;
//cout << (s1 == s3) << endl;
cout << (s2 >= s3) << endl;
cout << (s1 >= s2) << endl;
cout << (s1 >= s3) << endl;
}
void test_string4()
{
abl::string s1("helloxxxxxxxxxxx");
//abl::string s2;
//s2 = s1;
//cout << s1 << endl;
//cout << s2 << endl;
//s1.append(" world");
abl::string s2("worldxxx");
s1 = s2;
cout << s1 << endl;
cout << s2 << endl;
}
int main()
{
//test_string4();
string s("hello world");
string::iterator it = s.begin();
while (it != s.end())
{
*it = 'x';
it++;
}
cout << s << endl;
return 0;
}