?
前引:上一篇文章小編已經整理出了String的常用接口,梳理了各個接口的功能、參數,如何使用等各種實例。本篇文章將帶大家看看String這些接口的實踐使用,探索這些接口的實用性,是如何增加代碼效率的。在本篇文章的末尾,還奉上了部分底層的模擬實現,String類的使用是有趣的,下面我們來從實踐中感受String類帶給我們的快捷、效率!
目錄
string類的模擬實現
構造初始化
析構函數
流提取
流插入
大小比較
拷貝構造
賦值運算符重載
string類的模擬實現
下面我們來實現String的底層,解讀String的原理:
std庫里面的String有它的專屬空間,也就是C++庫
下面我們來命名自己的空間,同時String是一個類,我們需要實現:自定義空間+一個類
namespace Space
{class string{};
}
構造初始化
觀察庫里面的 string 初始化特點:
可以看到它的變量有三個:size、capacity、字符空間
下面我們來自己實現它的構造初始化:
初始化size、capacity、空間、存儲
//自定義構造
string(const char* allocator):_size(strlen(allocator)),_capacity(2*_size+1)
{try{_allocator = new char[_capacity];}catch (const exception& _allocator){cout << "空間開辟失敗" << endl;}//存儲strcpy(_allocator, allocator);
}
效果展示:
?可以看到是沒有問題的,但是我們平常是可能按下面的方式初始化的:
string S;
所以我們還得再寫一個無參默認構造,如下:
注意:不能是全缺省的,否則參數相同,編譯器無法區分
//默認構造
string():_size(0), _capacity(10)
{try{_allocator = new char[_capacity];}catch (const exception& _allocator){cout << "空間開辟失敗" << endl;}
}
以上我們的構造初始化就寫好了,可以隨時應對各種初始化情況,總代碼如下:
namespace Space
{class string{public://默認構造string():_size(0), _capacity(10){try{_allocator = new char[_capacity];}catch (const exception& _allocator){cout << "空間開辟失敗" << endl;}}//自定義構造string(const char* allocator):_size(strlen(allocator)),_capacity(2*_size+1){try{_allocator = new char[_capacity];}catch (const exception& _allocator){cout << "空間開辟失敗" << endl;}//存儲strcpy(_allocator, allocator);}private:size_t _size;size_t _capacity;char* _allocator;};
}
析構函數
這個函數很簡單,釋放空間,改變 size、capacity這些就可以了,如下:
//析構
~string()
{delete[]_allocator;_size = 0;_capacity = 0;cout << "釋放成功" << endl;
}
流提取
在上面我們已經實現了讀取函數,但是追求方便,且兩者有很大區別,比如:?
cout << S1.Read() << endl;
cout << S1 << endl;
ostream& operator<<(ostream& out, const string& _stl) //沒有找命名空間里面
{for (auto ac : _stl){cout << ac;}return out;
}
注意:不能在成員函數中實現,因為this指針會搶占第一個操作符位置,所以我們放在外面實現
區別:
C的字符數組,以\0為終止算長度
String不看\0,以size為終止長度,例如:
這樣看雖然沒有什么區別,但是如果添加上\0就有很大的變化了
可以看到流提取是不受\0影響的,所以我們需要注意這個點,字符的打印在流提取不受\0影響?
為什么流提取的實現需要以ostream&作為返回值
(1)允許多次連續提取
(2)避免流對象的開銷,規定直接傳引用
strcpy與memcpy的區別
特性 | strcpy | memcpy |
---|---|---|
參數類型 | char* | void* |
終止條件 | 遇到\0 停止 | 按指定字節數完成復制 |
長度控制 | 自動計算 | 顯式指定 |
數據安全 | 高風險 | 可控風險 |
適用場景 | 純字符串操作 | 任意內存數據復制 |
所以對于字符串我們需要根據形式區分二者的拷貝,否則會出很大的問題??
流插入
在模擬流插入時我們同樣要注意this指針的問題,因此需要在成員函數外面定義
我們看下面的問題:
注意(1):所以我們需要在輸入之前清理之前原本的字符,然后重置_size,效果如下:?
?注意(2):我們每次調用+=,都會開辟空間,效率可以優化,先存進數組里面,再最后統一拷? ? ? ? ? ? ? ? ? ? ? ? ?貝?
istream& operator>>(istream& in, string& _stl)
{//清理緩沖區_stl.clear();//輸入元素char c = in.get();//臨時數組int i = 0;char buff[128] = "\0";//直到c結束while (c != '\n' && c != '\0'){//先存入buff數組buff[i++] = c;//如果臨時數組滿了,就給_stlif (i == 127){memcpy(_stl._allocator, buff, i);//重置數組i = 0;}//_stl += c;//注意get會自動向后移動c = in.get();}//如果i沒有重置,說明沒有發生存滿if (i != 127){for (int j = 0; j < i; j++){//如果滿了就擴容if (_stl._size == _stl._capacity){_stl.reserve(2 * _stl._size);_stl._capacity = 2 * _stl._size;}//轉移到對象里面_stl._allocator[_stl._size++] = buff[j];}}return in;
}
效果展示:
大小比較
我們拿 > 舉例:大小比較我們一般采用的是運算符重載,里面根據當前字符的ASCII值比較
//大小比較
bool operator>(const string& S)const
{size_t p1 = 0, p2 = 0;//比較不同長度while (p1<_size && p2<S._size){if (_allocator[p1] == S._allocator[p2]){p1++;p2++;}else{if (_allocator[p1] > S._allocator[p2]){return true;}elsereturn false;}}//此時前面的字符都相等,但是沒有比較完if (p1 < _size){return true;}elsereturn false;return false;
}
效果展示:
拷貝構造
原理我就不說了,咱們直接實現:
//拷貝構造
string(const string& S)
{_allocator = new char[S._capacity];_size = S._size;_capacity = S._capacity;//數據拷貝memcpy(_allocator, S._allocator, S._capacity);
}
賦值運算符重載
將一個對象的內容賦給另一個對象,因為前面我們已經有了一定的了解,我們下面換一種玩法:
注意:如果沒有寫拷貝構造等,屬于淺拷貝,那么多次釋放同一個空間會出問題
我們知道swap可以交換任意形式的變量,所以我們先來實現一個可以交換對象的swap:
思路:先根據賦值對象A拷貝構造一個臨時對象B,然后把臨時對象B的數據給*this
void swap(const string& S)
{//先開辟空間,注意S出了swap函數會銷毀string tmp(S);//目的:創建一個臨時變量,把臨時變量的空間、大小等信息轉給Sstd:: swap(_allocator, tmp._allocator);std:: swap(_size, tmp._size);std:: swap(_capacity, tmp._capacity);
}
下面我們直接調用這個swap函數就OK了:
string& operator=(string& S)
{(*this).swap(S);return *this;
}
效果展示:
最后我們再梳理以下思路:
現在有兩個對象:A和B,我們的目標是A=B
進入swap函數先以B為模板調用拷貝構造出C,此時C是臨時對象,內容與B完全一致
然后將C的內容交換給A,C雖然會釋放,但是它在堆上開的內容只會main函數調用析構才會釋放
?
這里我們先完成構造、析構,由于排版問題,下一篇我們來完成它的功能結尾!
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? 【霧非霧】期待與你的下次相遇!?