赞
踩
namespace lyx
{
//模拟实现string类
class string
{
}
}
string 实际上就是一个类,我们在使用时,实例化这个类,并且调用其中的函数。
我们将成员变量私有化,成员函数公有化,留作接口,供外部使用:
class string
{
public:
//成员函数
private:
char* _str;
size_t _size;
size_t _capacity;
//npos 是一个常数,用来表示不存在的位置(参考string库的设置)
const static size_t npos = -1;
}
字符串的底层实际就是一个字符数组,既然是数组,我们就可以通过以下方式去访问:
string a="hello world"
cout<<a[1]; //e
因此要实现这种访问方式,就要进行运算符重载:
//重载[]
//(1)普通对象:可读可写
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
//(2)const对象:只读
char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
后const修饰成员变量不能被修改
前const修饰成员函数返回值不能被修改
想对字符串进行增删查改,得先另外开辟一段空间(在堆上),再将str指向的字符串拷贝到这段空间:
string(const char* str = "")
{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity+1];
strcpy(_str, str);
}
析构函数:
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
string迭代器是指针,因为字符串是连续的地址空间。但不是所有的迭代器都是指针,因为不是所有的容器都是连续的。
typedef char* iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
对于某些函数(例如printf函数),我们希望对字符串只读,因此会调用const迭代器
typedef const char* const_itertor;
const_itertor begin() const
{
return _str;
}
const_itertor end() const
{
return _str + _size;
}
首先由类和对象的知识,拷贝构造函数一定是引用返回。但默认生成的拷贝构造函数是浅拷贝,会导致S1和S2对象指向同一块地址空间,在先释放掉S2所指向空间后,再调用析构函数释放S1的空间,这段空间已经不存在了,程序会崩溃。因此需要自定义一个拷贝构造函数。
即先给S2开辟一段新的空间,再将S1拷贝给S2
传统写法:
//s2(s1)
string(const string& s)
{
_str = new char[s._capacity+1];
_capacity = s._capacity;
_size = s._size;
strcpy(_str, s._str);
}
这里需要注意:拷贝构造函数的参数只有一个且必须是类类型对象的引用。 使用传值方式编译器直接报错,因为会引发无穷递归调用。同时为了防止S1引用被改变而导致s1的改变,还加了const。
现代写法:
string(const string& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
string tmp(s._str);
swap(tmp);
}
即先创建一个对象tmp,调用构造函数,使用s._str去初始化tmp,也就是_str开辟的空间的内容与s相同。
这个时候 tmp指向的空间就是 s2 想要的,所以我用swap 将s2._st(也就是this ->_str),和tmp._str交换,此时s2就指向了tmp原来指向的空间,效果上实现了深拷贝。
此时,tmp就指向了s2._str原来指向的空间,而s2在之前被我们初始化为nullptr了,所以在之后析构tmp的时候不会报错(delete nullptr 是被允许的)。
将S3赋值给S1,可能会出现两种情况:1.S1长度小于S2,把S2给S1会造成越界;2.S1长度大于S2,把S2给S1会造成资源浪费。
//s1=s3 string& operator=(const string& s) { //内容相同不赋值 if (this != &s) { char* tmp = new char[s._capacity + 1]; strcpy(tmp, s._str); delete[] _str; _str = tmp; _size = s._size; _capacity = s._capacity; } }
因此,先开辟一段空间,再将S3的数据拷贝到S1指向的新空间中。再释放S1原来的空间。
也可以通过swap函数实现,思想与拷贝构造函数类似。
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n+1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
resize 和 reserve 的区别在于在开辟空间的时候会对空间初始化。所以我们需要在形参列表中加上一个char型字符,用来填充我们新开的空间。
当然,如果n小于_size,我们要将字符串截取到n长度
void resize(size_t n, char ch = '\0') { if (n > _size) { reserve(n); for (size_t i = _size; i < n; ++i) { _str[i] = ch; } _size = n; _str[_size] = '\0'; } else { _str[n] = '\0'; _size = n; } }
void push_back(char ch)
{
if (_size == _capacity)
{
size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
reserve(newCapacity);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len < _capacity)
{
reserve(_size + len);
}
strcpy(_str + _size, str);
_size += len;
}
strcpy(_str + _size, str)的意思是把str复制到_str+_size之后的位置
_str+_size指向‘\0’,然后把str复制过去,就连接上了。
插入一个字符
string& insert(size_t pos, char ch) { assert(pos <= _size); if (_size == _capacity) { size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newCapacity); } size_t end = _size + 1; while (end > pos) { _str[end] = _str[end - 1]; --end; } _str[pos] = ch; ++_size; return *this; }
插入一个字符串
string& insert(size_t pos, const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } size_t end = _size + len; while (end > pos + len - 1) { _str[end] = _str[end - len]; --end; } strncpy(_str + pos, str, len); _size += len; return *this; }
string& erase(size_t pos, 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 -= pos; } return *this; }
string.h
#pragma once #include <iostream> #include <string.h> #include <assert.h> using namespace std; namespace lyx { class string { public: //--------------------------------------iterators------------------------------------// 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; } //---------------------------member functions-------------------------------// //' '单引号表示单个字符,这里表示转义字符终止符 //" "双引号表示字符串常量 //空字符常量使用转义符号 '\0'表示,空白字符串使用双引号表示 "" //无论"\0"和'\0'都会转义,除非"a\\0a" -- a\0a //构造函数 /*string(const char* str = "") { _size = strlen(str); _capacity = _size; _str = new char[_capacity+1]; strcpy(_str, str); }*/ string(const char* str = "") { int len = strlen(str); _size = _capacity = len; //capacity记录有效字符的个数 _str = new char[_capacity + 1]; //留一个空间给'\0' strcpy(_str, str); } // s2(s1) // 传统写法 //string(const string& s) //{ // _str = new char[s._capacity+1]; // _capacity = s._capacity; // _size = s._size; // strcpy(_str, s._str); //} //拷贝构造--现代写法 string(const string& s) :_str(nullptr) , _size(0) , _capacity(0) { string tmp(s._str); swap(tmp); } //s1=s3 //string& operator=(const string& s) //{ // //内容相同不赋值 // if (this != &s) // { // char* tmp = new char[s._capacity + 1]; // strcpy(tmp, s._str); // delete[] _str; // _str = tmp; // _size = s._size; // _capacity = s._capacity; // } //} //赋值重载--现代写法1 //string& operator=(const string& s) //{ // if (this == &s) //检查自我赋值 // return *this; // string tmp(s); // swap(tmp); // return *this; //} //赋值重载--现代写法2 string& operator=(string s) { swap(s); return *this; } ~string() { delete[] _str; _str = nullptr; _size = _capacity = 0; } //---------------------------------------Capacity--------------------------------------// size_t size() const { return _size; } size_t capacity() const { return _capacity; } 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) { reserve(n); for (size_t i = _size; i < n; ++i) { _str[i] = ch; } _size = n; _str[_size] = '\0'; } else { _str[n] = '\0'; _size = n; } } void clear() { _size = 0; _str[_size] = '\0'; } bool empty() const { return _size == 0; } //---------------------------------------Modify----------------------------------------// //重载[] //(1)普通对象:可读可写 char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; } //(2)const对象:只读 char& operator[](size_t pos) const { assert(pos < _size); return _str[pos]; } void push_back(char ch) { if (_size == _capacity) { size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newCapacity); } _str[_size] = ch; ++_size; _str[_size] = '\0'; } void pop_back() { _size--; _str[_size] = '\0'; } void append(const char* str) { size_t len = strlen(str); if (_size + len < _capacity) { reserve(_size + len); } strcpy(_str + _size, str); _size += len; } //+=一个字符 string& operator+=(char ch) { push_back(ch); return *this; } //+=一个字符串 string& operator+=(const char* str) { append(str); return *this; } //插入一个字符 string& insert(size_t pos, char ch) { assert(pos <= _size); if (_size == _capacity) { size_t newCapacity = _capacity == 0 ? 5 : _capacity * 2; reserve(newCapacity); } size_t end = _size + 1; while (end > pos) { _str[end] = _str[end - 1]; --end; } _str[end] = ch; ++_size; return *this; } //插入一个字符串 string& insert(size_t pos, const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } size_t end = _size + len; while (end > pos + len - 1) { _str[end] = _str[end - len]; --end; } strncpy(_str + pos, str, len); _size += len; return *this; } string& erase(size_t pos, 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 -= pos; } return *this; } //交换两个字符串 void swap(string& s) { std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); } //----------------------------------------String operations-----------------------------// const char* c_str() const { return _str; } size_t find(char ch, size_t pos = 0) const { assert(pos < _size); while (pos < _size) { if (_str[pos] == ch) { return pos; } ++pos; } return npos; } size_t find(const char* str, size_t pos = 0) const { assert(pos < _size); //strstr函数搜索一个字符串在另一个字符串中的第一次出现 const char* ptr = strstr(_str + pos, str); if (ptr == nullptr) { return npos; } else { return ptr - _str; } } //---------------------------------Non-member function overloads----------------------------// friend ostream& operator<<(ostream& out, const string& s); friend istream& operator>>(istream& in, string& s); friend istream& getline(istream& in, string& s); private: char* _str; size_t _size; size_t _capacity; const static size_t npos = -1; }; //-----------------方便自定义类型打印---------------------// //流插入重载 inline ostream& operator<<(ostream& out, const string& s) { for (size_t i = 0; i < s._size; ++i) { out << s._str[i]; } return out; } //流提取重载 14--2:54 inline istream& operator>>(istream& in, string& s) { s.clear(); //char ch = in.get(); //while (ch != ' ' && ch != '\n')//cin遇到空格或\n结束 //{ // s += ch; // ch = in.get(); //} //优化 char buff[128] = { '\0' }; size_t i = 0; char ch = in.get(); while (ch != ' ' && ch != '\n') { if (i == 127) { s += buff; i = 0; } buff[i++] = ch; ch = in.get(); } if (i > 0) { buff[i] = '\0'; s += buff; } return in; } istream& getline(istream& in, string& s) { char buff[128] = { '\0' }; size_t i = 0; char ch = in.get(); while (ch != '\n') { if (i == 127) { s += buff; i = 0; } buff[i++] = ch; ch = in.get(); } if (i > 0) { buff[i] = '\0'; s += buff; } return in; } }
Test.cpp
#define _CRT_SECURE_NO_WARNINGS #include "string.h" void Test_String1() { //构造 lyx::string s1; lyx::string s2("abcdef"); //拷贝构造 lyx::string s3 = s2; //赋值重载 s1 = s2; } void Test_String2() { lyx::string s1("12345"); lyx::string::iterator it = s1.begin(); /*for (it; it < s1.end(); ++it) (*it)++;*/ cout << s1.c_str() << endl; const lyx::string s2("67890"); lyx::string::const_iterator it2 = s2.begin(); /*for (it2; it2 < s2.end(); ++it2) (*it2)++;*/ cout << s2.c_str() << endl; } void Test_String3() { lyx::string s("hello world"); cout << s.c_str() << endl; cout << s.size() << endl; cout << s.capacity() << endl; s.resize(5); cout << s.size() << endl; cout << s.capacity() << endl; cout << s.c_str() << endl; s.reserve(15); cout << s.size() << endl; cout << s.capacity() << endl; cout << s.c_str() << endl; s.resize(20, 'x'); cout << s.size() << endl; cout << s.capacity() << endl; cout << s.c_str() << endl; } void Test_String4() { /*lyx::string s = "hello world"; s.push_back('!'); cout << s.c_str() << endl; s.append("xxxxxxx"); cout << s.c_str() << endl; s += '6'; cout << s.c_str() << endl; s += "123456"; cout << s.c_str() << endl;*/ lyx::string s1 = "hello w"; s1.insert(3,'x'); cout << s1.c_str() << endl; s1.insert(2, "555"); cout << s1.c_str() << endl; lyx::string s2 = "hello world"; s2.erase(3, 3); cout << s2.c_str() << endl; } void Test_String5() { lyx::string s = ("abcefeefeefe"); cout << s.find('f',3) << endl; cout << s.find('f') << endl; cout << s.find("efe", 3) << endl; cout << s.find("efe") << endl; } void Test_String6() { lyx::string s; //lyx::string s = ("hello world"); cin >> s; cout << s << endl; } int main() { //Test_String1(); //Test_String2(); //Test_String3(); //modify //Test_String4(); //string operations //Test_String5(); Test_String6(); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。