文章目錄
- 1、string類的出現
- 1.1 C語言中的字符串
- 2、標準庫中的string類
- 2.1 string類
- 3、string類的常見接口說明及模擬實現
- 3.1 string的常見構造
- 3.2 string的構造函數
- 3.3 string的拷貝構造
- 3.4 string的賦值構造
- 4、完整代碼
1、string類的出現
1.1 C語言中的字符串
C語言中,字符串是以’\0’結尾的一些字符的集合,為了操作方便,C標準庫中提供了一些str系列的庫函數,但是這些庫函數與字符串是分離開的,不太符合面向對象的思想,而且底層空間需要用戶自己管理,稍不留神可能還會越界訪問。
因此C++中,為了讓我們更簡單、方便、快捷的使用字符串類型,C++提供了string類。
2、標準庫中的string類
2.1 string類
string類文檔介紹
string類在使用的時候我們需要包含頭文件 #include ,以及using namespace std;
- 字符串是表示字符序列的類。
- 標準的字符串類提供了對此類對象的支持,其接口類似于標準字符容器的接口,但添加了專門用于操作單字節字符字符串的設計特性。
- string類是使用char(即作為它的字符類型,使用它的默認char_traits和分配器類型(關于模板的更多信息,請參閱basic_string)。
- string類是basic_string模板類的一個實例,它使用char來實例化basic_string模板類,并用char_traits和allocator作為basic_string的默認參數(根于更多的模板信息請參考basic_string)。
- 注意,這個類獨立于所使用的編碼來處理字節:如果用來處理多字節或變長字符(如UTF-8)的序列,這個類的所有成員(如長度或大小)以及它的迭代器,將仍然按照字節(而不是實際編碼的字符)來操作。
總結:
1. string是表示字符串的字符串類。
2. 該類的接口與常規容器的接口基本相同,再添加了一些專門用來操作string的常規操作。
3. string在底層實際是:basic_string模板類的別名,
typedef basic_string<char, char_traits, allocator>string;
4. 不能操作多字節或者變長字符的序列。
3、string類的常見接口說明及模擬實現
3.1 string的常見構造
(constructor)函數名稱 | 功能說明 |
---|---|
string() | 構造空的string類對象,即空字符串 |
string(const char* s) | 用C-string來構造string類對象 |
string(size_t n, char c) | string類對象中包含n個字符c |
string(const string&s) | 拷貝構造函數 |
int main()
{string s1; // 構造空的string類對象s1string s2("hello"); // 用C格式字符串構造string類對象s2string s3(s2); // 拷貝構造s3return 0;
}
3.2 string的構造函數
namespace s
{class string{public://string()// :_str(new char[1]{ '\0' })//這里開一個空間,并賦值為\0,如果直接賦值為nullptr的話// ,_size(0) //在實例化一個無參對象后,對對象進行操作的時候會引發空指針異常// ,_capacity(0)//{}//全缺省構造函數string(const char* str = "")//常量字符串默認以\0結尾,因此不需要給: _size(strlen(str)), _capacity(_size){_str = new char[_capacity + 1];//多開一個空間,需要存放\0strcpy(_str, str);//將字符串拷貝到_str}private:char* _str;size_t _size;//有效存儲字符個數size_t _capacity;//實際空間};
}
這里我們用一個全缺省將無參構造與構造都包括了。
這個構造函數很簡單,這里就不多講了,大家應該可以看懂。
3.3 string的拷貝構造
傳統寫法:
//拷貝構造
string(const string& s): _size(strlen(s._str)), _capacity(_size)
{_str = new char[_capacity + 1];strcpy(_str, s._str);
}
現代寫法:
void swap(string& s)
{std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);
}
//現代寫法 s1(s2)
string(const string& s):_str(nullptr),_size(0),_capacity(0)
{string tmp(s._str);//構造swap(tmp);//this->swap(s);
}
庫里提供了交換函數,我們封裝一個交換函數,內部的實現就使用庫里面的swap,我們拷貝構造函數里面先調用構造函數,實例化一個tmp,再將tmp與this交換。
3.4 string的賦值構造
傳統寫法:
string& operator=(const string& s)
{if (this != &s){string tmp(s);//拷貝構造swap(tmp);}return *this;
}
現代寫法:這里與拷貝構造的現代寫法是類似的,不再多說。
void swap(string& s)
{std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);
}
string& operator=(const string& s)
{if (this != &s){string tmp(s);//拷貝構造swap(tmp);}return *this;
}
我們其實可以對現代寫法繼續精簡一下,我們這里參數是引用傳參,我們不用引用就會產生一次拷貝,對拷貝的形參直接進行交換,這樣就可以簡化寫法,但是這里的效率其實是一樣的,都是一次拷貝構造 + 一次交換。
// 極致寫法,效率與上面一樣
string& operator=(string tmp)//參數直接調用拷貝構造
{swap(tmp);return *this;
}
4、完整代碼
#include <string.h>
#include <algorithm>
using namespace std;namespace s
{class string{public://string()// :_str(new char[1]{ '\0' })//這里開一個空間,并賦值為\0,如果直接賦值為nullptr的話// ,_size(0) //在實例化一個無參對象后,對對象進行操作的時候會引發空指針異常// ,_capacity(0)//{}//全缺省構造函數string(const char* str = "")//常量字符串默認以\0結尾,因此不需要給:_size(strlen(str)),_capacity(_size){_str = new char[_capacity + 1];//多開一個空間,需要存放\0strcpy(_str, str);//將字符串拷貝到_str}//拷貝構造// 傳統寫法//string(const string& s)// :_size(s._size)// ,_capacity(s._capacity)//{// _str = new char[s._capacity + 1];// strcpy(_str, s._str);//}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}//現代寫法 s1(s2)string(const string& s):_str(nullptr),_size(0),_capacity(0){string tmp(s._str);//構造swap(tmp);//this->swap(s);}//賦值// 傳統寫法//string& operator=(const string& s)//{// if (this != &s)// {// char* tmp = new char[s._capacity];// strcpy(tmp, s._str);// delete[] _str;// _str = tmp;//將tmp字符串直接給_str,類似淺拷貝// _size = s._size;// _capacity = s._capacity;// }// return *this;//}//現代寫法//string& operator=(const string& s)//{// if (this != &s)// {// string tmp(s);//拷貝構造// swap(tmp);// }// return *this;//}// 極致寫法,效率與上面一樣string& operator=(string tmp)//參數直接調用拷貝構造{swap(tmp);return *this;}~string(){cout << "~string()" << endl;delete[] _str;_size = _capacity = 0;}private:char* _str;size_t _size;//有效存儲字符個數size_t _capacity;//實際空間};
}