在学习C++时,我们发现string这个类功能很强大,所以我们模拟实现以下它,虽然不能像库函数里实现的那么强大和完美,但是有助于我们更加熟悉的使用string。此篇博客我将用深度拷贝来实现。这里深度拷贝简单来说就是除了拷贝对象的值以外,若对象有其所指向的一块空间,则同时为新创建的对象也开辟一块空间,再拷贝内容。除了深度拷贝,写时拷贝也能实现string类,并且写时拷贝更加高效,写时拷贝具体是什么,我将再下篇用写时拷贝实现string类进行介绍。
这里我简单的实现了string类的基本函数和几个功能函数:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstring>
#include<cassert>
using namespace std;
class String
{
friend ostream& operator<<(ostream &os, const String &s);
public:
String(char *str = "")
:_str(new char[strlen(str) + 1]), _sz(strlen(str)), _capacity(strlen(str) + 1)
{
strcpy(_str, str);
}
~String()
{
if (_str != NULL)
{
delete[] _str;
_sz = 0;
_capacity = 0;
}
}
String(const String &s)
:_str(new char[strlen(s._str) + 1])
{
_sz = s._sz;
_capacity = s._capacity;
strcpy(_str, s._str);
}
String& operator=(String s) //赋值运算符重载的现代写法
{
_sz = s._sz;
_capacity = s._capacity;
std::swap(s._str, _str);
return *this;
}
const char *c_str()
{
return _str;
}
void CheckCapacity(int sz) //检测容量是否够用,不够则重新开辟
{
int tmp = 0;
if (_capacity<(sz + _sz + 1))
{
tmp = (2 * _capacity > _capacity + sz) ? 2 * _capacity : _capacity + sz;
char *str = new char[_capacity];
strcpy(str, _str);
delete[] _str;
_str = new char[tmp];
strcpy(_str, str);
_capacity = tmp;
}
}
void PushBack(char ch) //尾部插入字符
{
CheckCapacity(1);
_str[_sz++] = ch;
_str[_sz] = '\0';
_sz += 1;
}
char operator[](int sz)
{
return _str[sz];
}
String &operator+=(const String&s)
{
CheckCapacity(strlen(s._str));
strcat(_str, s._str);
return *this;
}
size_t find(const String& s, size_t pos = 0) const //在一个字符串里查找子串,返回第一次出现的位置下标
{
char *str1 = _str;
char *src = _str;
char *str2 = s._str;
int count = 1;
while (*src)
{
str2 = s._str;
str1 = src;
while ((*str1) && (*str2) && (*str1 == *str2))
{
str1++;
str2++;
}
if (*str2 == '\0')
{
return count;
}
count++;
src++;
}
return 0;
}
String& Insert(size_t pos1, const String& s) //给定位置插入字符串
{
//assert((pos1 > 0) || (pos1 < strlen(_str + 1)));
CheckCapacity(strlen(s._str));
char *tmp = new char[strlen(_str)];
strcpy(tmp, _str + pos1-1);
_str[pos1 - 1] = '\0';
*this += s;
strcat(_str, tmp);
_sz += strlen(s._str);
return *this;
}
private:
char *_str;
int _sz;
int _capacity;
};
ostream& operator<<(ostream &os, const String &s)
{
os << s._str;
return os;
}
void test1() //测试拷贝构造
{
String s1("hello");
String s2(s1);
cout << s2 << endl;
}
void test2() //测试赋值操作符
{
String s1("hello");
String s2;
s2 = s1;
cout << s2 << endl;
}
void test3() //测试+=操作符重载
{
String s1("hello");
String s2(" world");
s1 += s2;
cout << s1 << endl;
}
void test4() //测试pushback函数
{
String s1("worl");
s1.PushBack('d');
cout << s1 << endl;
}
void test5() //测试find函数
{
String s1("hello world");
String s2("world");
int ret = s1.find(s2);
cout << ret << endl;
}
void test6() //测试[]运算符重载
{
String s1("hello world");
cout << s1[2] << endl;
}
void test7() //测试insert函数
{
String s1("hello");
s1 = s1.Insert(2, " world");
cout << s1 << endl;
}
int main()
{
test1();
test2();
test3();
test4();
test5();
test6();
test7();
getchar();
return 0;
}
私有成员除了一个char* 类型的字符串,还有一个_sz(字符串的长度)和_capacity(字符串开辟空间的大小)来维护字符串。在需要插入字符或者字符串的时候,需要先检测空间大小是否足够,不够则需要重新开辟空间,这时候需要用到_sz,_capacity。
除了以上这些功能,库里的string其实有更多的功能,感兴趣可以点击这个链接自己搜索看看:http://www.cplusplus.com/