string的文檔介紹
- string是表示字符序列的類
- 標準的字符串類提供了對此類對象的支持,其接口類似於標準字符容器的接口,但添加了專門用於操作 單字節字符字符串的設計特性。
- string類是使用char(即作爲它的字符類型,使用它的默認char_traits和分配器類型(關於模板的更多信 息,請參閱basic_string)。
- string類是basic_string模板類的一個實例,它使用char來實例化basic_string模板類,並用char_traits
和allocator作爲basic_string的默認參數(根於更多的模板信息請參考basic_string)。- 注意,這個類獨立於所使用的編碼來處理字節:如果用來處理多字節或變長字符(如UTF-8)的序列,這個 類的所有成員(如長度或大小)以及它的迭代器,將仍然按照字節(而不是實際編碼的字符)來操作。
下面就來模擬實現一個具備常用功能的String類
實現的接口:
默認成員函數部分
string(const char* str = ""); //全缺省構造函數
string(const string& s); //拷貝構造函數
~string(); //析構函數
string& operator=(const string& s);
迭代器部分
//用指針模擬實現迭代器
typedef char* iterator;
typedef const char* const_iterator;
iterator begin(); //首部迭代器
iterator end(); //尾部迭代器
const_iterator cbegin() const; //首部常量迭代器
const_iterator cend() const; //尾部常量迭代器
容量部分
size_t capacity() const;
size_t size() const;
bool empty() const;
void resize(size_t newSize, char c = '\0');
void reserve(size_t newCapacity);
元素訪問部分
char& operator[](size_t index);
const char& operator[](size_t index) const;
關係運算符部分
bool operator<(const string& s);
bool operator<=(const string& s);
bool operator>(const string& s);
bool operator>=(const string& s);
bool operator==(const string& s);
bool operator!=(const string& s);
字符串操作部分
const char* c_str() const;
size_t find(char c, size_t pos = 0) const;
size_t find(const char* s, size_t pos = 0) const;
IO部分
friend std::ostream& operator<<(std::ostream& _cout, const string& s);
friend std::istream& operator>>(std::istream& _cin, string& s);
修改部分
static size_t npos;
string& insert(size_t pos, char c);
string& insert(size_t pos, const char* str);
string& erase(size_t pos, size_t len = npos);
void push_back(char c);
void pop_back();
string& operator+=(char c);
string& operator+=(const char* str);
void append(const char* str);
void clear();
void swap(string& s);
私有成員
size_t _size;
size_t _capacity;
char* _str;
代碼實現
因爲代碼有點多就不分開介紹了,所有的思路都寫在註釋裏
#pragma once
#include<iostream>
#include<cstring>
#include<cassert>
namespace lee
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
friend std::ostream& operator<<(std::ostream& _cout, const string& s);
friend std::istream& operator>>(std::istream& _cin, string& s);
//構造函數
string(const char* str = "")
: _size(strlen(str))
, _capacity(_size)
, _str(new char[_size + 1])
{
strcpy(_str, str);
}
/*
//拷貝構造函數
//傳統寫法開空間拷數據
string(const string& s)
: _size(s._size)
, _capacity(s._capacity)
, _str(new char[_size + 1])
{
strcpy(_str, s._str);
}
*/
//現代寫法,直接構造一個臨時對象,然後和那個臨時對象進行交換,交換過去的數據在函數結束便銷燬
string(const string& s)
: _size(0)
, _capacity(0)
, _str(nullptr)
{
string temp(s._str);
swap(temp);
}
/*
//傳統寫法,開空間拷貝數據
string& operator=(const string& s)
{
//相同則不交換
if (this != &s)
{
char* str = new char[strlen(s._str) + 1];
strcpy(str, s._str);
delete[] _str;
_str = str;
}
return *this;
}
*/
//現代寫法,直接用構造函數構建然後交換
string& operator=(const string& s)
{
string temp(s._str);
swap(temp);
return *this;
}
//析構函數
~string()
{
_size = _capacity = 0;
delete[] _str;
_str = nullptr;
}
/*
------------------------------------------------------------
容量部分
Capacity
------------------------------------------------------------
*/
//返回capacity
size_t capacity() const
{
return _capacity;
}
//返回size
size_t size() const
{
return _size;
}
//如果爲空返回true,不爲空返回false
bool empty() const
{
return !_size;
}
//重新分配size
void resize(size_t newSize, char c = '\0')
{
//如果size不夠,擴容
if (_size < newSize)
{
//如果capacity不夠,調用reserve擴容
if (_capacity < newSize)
{
reserve(newSize);
}
//將多出的空間全部初始化爲c
memset(_str + _size, c, newSize - _size);
}
//當空間夠的時候,直接截斷數據
_size = newSize;
_str[_size] = '\0';
}
//重新分配capacity
void reserve(size_t newCapacity)
{
if (_capacity >= newCapacity)
return;
char* str = new char[newCapacity + 1];
strcpy(str, _str);
delete[] _str;
_str = str;
_capacity = newCapacity;
}
/*
------------------------------------------------------------
迭代器部分
Iterators:
------------------------------------------------------------
*/
//首部迭代器啊
iterator begin()
{
return _str;
}
//尾部迭代器
iterator end()
{
return _str + _size;
}
//首部常量迭代器
const_iterator cbegin() const
{
return _str;
}
//尾部常量迭代器
const_iterator cend() const
{
return _str + _size;
}
/*
------------------------------------------------------------
修改部分
Modifiers:
------------------------------------------------------------
*/
//在某個位置後插入字符
string& insert(size_t pos, char c)
{
assert(pos < _size);
if (_capacity == _size)
{
size_t newcapacity = (_capacity == 0) ? 2 : 2 * _capacity;
reserve(newcapacity);
}
//數據後移
for (size_t i = _size; i > pos; i--)
{
_str[i] = _str[i - 1];
}
_str[pos] = c;
_str[++_size] = '\0';
return *this;
}
//在某個位置後插入字符串
string& insert(size_t pos, const char* str)
{
assert(pos < _size);
size_t size = strlen(str);
//檢查容量,不夠就擴容
if (size + _size > _capacity)
{
reserve(size + _size);
}
//數據後移size個位置
for (size_t i = _size + size - 1; i > pos + size - 1; i--)
{
_str[i] = _str[i - size];
}
//拷貝數據到第pos個位置
memcpy(_str + pos, str, size);
_size += size;
return *this;
}
// 刪除pos位置上的元素,並返回該元素的下一個位置
string& erase(size_t pos, size_t len = npos)
{
//如果那個位置後面沒有那麼多數據,就直接從那個位置截斷,刪除後面所有數據
if (len >= _size - pos)
{
_str[pos] = '\0';
_size = pos;
}
else
{
//從數據刪除後前移pos個位置
for (size_t i = pos + len; i <= _size; i++)
{
_str[i - len] = _str[i];
}
}
//重新設置size和結尾的\0
_size -= len;
_str[_size] = '\0';
return *this;
}
//尾插
void push_back(char c)
{
if (_capacity == _size)
{
size_t newcapacity = (_capacity == 0) ? 2 : 2 * _capacity;
reserve(newcapacity);
}
_str[_size++] = c;
_str[_size] = '\0';
}
//尾刪
void pop_back()
{
_str[--_size] = '\0';
}
//追加字符
string& operator+=(char c)
{
push_back(c);
return *this;
}
//尾部追加字符串
void append(const char* str)
{
size_t size = strlen(str);
//檢查容量,不夠就擴容
if (size + _size > _capacity)
{
reserve(size + _size);
}
//尾部追加字符串
strcpy(_str + _size, str);
_size += size;
}
//追加字符串
string& operator+=(const char* str)
{
append(str);
return *this;
}
//清空string
void clear()
{
_size = 0;
_str[_size] = '\0';
}
//交換string
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
/*
------------------------------------------------------------
元素訪問部分
Element access:
------------------------------------------------------------
*/
char& operator[](size_t index)
{
assert(index < _size);
return _str[index];
}
const char& operator[](size_t index) const
{
assert(index < _size);
return _str[index];
}
/*
------------------------------------------------------------
關係運算符
relational operators:
------------------------------------------------------------
*/
bool operator<(const string& s)
{
if (strcmp(_str, s._str) == -1)
return true;
else
return false;
}
bool operator<=(const string& s)
{
return (*this < s) || (*this == s);
}
bool operator>(const string& s)
{
return !(*this <= s);
}
bool operator>=(const string& s)
{
return !(*this < s);
}
bool operator==(const string& s)
{
if (strcmp(_str, s._str) == 0)
return true;
else
return false;
}
bool operator!=(const string& s)
{
return !(*this == s);
}
/*
------------------------------------------------------------
字符串操作
String operations:
------------------------------------------------------------
*/
//返回C風格的字符串
const char* c_str() const
{
return _str;
}
//查找字符c第一次出現的位置
size_t find(char c, size_t pos = 0) const
{
assert(pos < _size);
size_t i = pos;
while (i < _size)
{
if (_str[i] == c)
return i;
i++;
}
return npos;
}
// 返回子串s在string中第一次出現的位置
size_t find(const char* s, size_t pos = 0) const
{
const char* src = _str;
const char* sub = s;
while (*src)
{
//如果兩個位置匹配則繼續遍歷
while (*src == *sub && *sub)
{
src++;
sub++;
}
//如果sub走完就說明完全匹配,返回sub第一次出現的位置
if ('\0' == *sub)
{
return (src - _str - strlen(s));
}
//不匹配則回溯,繼續匹配下一個位置
else
{
sub = sub;
src = ++src;
}
}
return npos;
}
private:
size_t _size;
size_t _capacity;
char* _str;
static size_t npos;
};
size_t string::npos = -1;
std::ostream& operator<<(std::ostream& out, const string& s)
{
out << s._str;
return out;
}
std::istream& operator>>(std::istream& in, string& s)
{
//直接用cin輸入進str會有無法擴容的問題,需要手動擴容
while (1)
{
char ch;
ch = in.get();
//遇到分隔符則暫停
if (ch == '\n' || ch == ' ')
{
break;
}
else
{
s.push_back(ch);
}
}
return in;
}
}