C++ String部分成員模擬實(shí)現(xiàn)流程詳解
string類的成員設(shè)計(jì)
class string { private: char* _str; int _size; int _capacity; };
說明:以下的五個(gè)成員函數(shù)的模擬實(shí)現(xiàn),均去除了_size
和_capacity
成員變量,目的是為了更方便解釋重點(diǎn)。在五個(gè)成員函數(shù)模擬后,會(huì)對(duì)string類的設(shè)計(jì)進(jìn)行補(bǔ)全。
普通構(gòu)造函數(shù)的模擬
我們是否可以使用默認(rèn)構(gòu)造函數(shù)來初始化對(duì)象?在這種情況下是萬萬不能的!要記住默認(rèn)的構(gòu)造函數(shù)對(duì)自定義類型會(huì)去調(diào)用它自己的構(gòu)造函數(shù)進(jìn)行初始化,而對(duì)于內(nèi)置類型是不做處理的,此時(shí)我們的成員變量_str
的類型是內(nèi)置類型,不會(huì)被初始化,所以一定要自己寫構(gòu)造函數(shù)。
//這種構(gòu)造函數(shù)是否可行? string(const char* str) { _str = str; }
這種寫法做不到用字符串構(gòu)造一個(gè)對(duì)象。
原因:這樣會(huì)使得str
和_str
指向的都是同一塊空間。str會(huì)影響到_str.
所以正確的做法是,給_str
分配一塊屬于自己的空間,再把str
的值拷貝給_str.
string(const char* str) { _str = new char[strlen(str) + 1]; //要多給一個(gè)'\0'的空間 strcpy(_str, str); }
修一下小細(xì)節(jié):
1.實(shí)例化對(duì)象的時(shí)候是支持無參構(gòu)造的,所以可以給參數(shù)一個(gè)缺省值""
,里面自己隱藏的有一個(gè)\0
.如果沒有傳參數(shù),則使用缺省值。
string(const char* str = "") { _str = new char[strlen(str) + 1]; //要多給一個(gè)'\0'的空間 strcpy(_str, str); }
拷貝構(gòu)造函數(shù)的模擬
看了普通構(gòu)造函數(shù)的模擬實(shí)現(xiàn)以后,最不應(yīng)該犯的錯(cuò)就是把一個(gè)string對(duì)象的數(shù)據(jù)直接給了另一個(gè)string對(duì)象
所以直接甩代碼
string(const string& s) { _str = new char[strlen(s._str) + 1]; strcpy(_str, s._str); }
當(dāng)然,如果有前面所寫普通構(gòu)造函數(shù),還可以利用普通構(gòu)造函數(shù)來拷貝構(gòu)造一個(gè)對(duì)象。
//還可以借助普通構(gòu)造函數(shù) string(const string& s) :_str(nullptr) { string tmp(s._str); swap(_str, tmp._str); }
賦值重載函數(shù)的模擬
這里重載賦值,是為了把一個(gè)已經(jīng)存在的string對(duì)象的數(shù)據(jù)給另一個(gè)已經(jīng)存在的string對(duì)象。
也就意味著,兩個(gè)對(duì)象均有自己的空間。不要把string對(duì)象的_str直接賦值,否則析構(gòu)的時(shí)候會(huì)析構(gòu)兩次,并且這兩個(gè)string對(duì)象由于_str使用的是同一塊空間,會(huì)相互之間影響。
string& operator=(const string& s) { delete[] _str; //把原來的空間釋放掉 _str = new char[strlen(s._str) + 1]; //給一塊新的空間 strcpy(_str, s._str);; }
上面這種方法是不行的。
1.不排除自己給自己賦值的情況,自己都給釋放了,拿什么來賦值?
2.使用delete先釋放,只要地址正確無論如何都會(huì)釋放成功,但是new
一塊空間不一定會(huì)成功,如果一開始就給釋放了,而我去申請(qǐng)空間卻申請(qǐng)不到,那就是不僅沒有賦值成功,還把我自己原本有的給丟了。
//正確的寫法 string& operator=(const string& s) { if (this != &s) { char* tmp = new char[strlen(s._str) + 1]; strcpy(tmp, s._str); delete[] _str; _str = tmp; } return *this; //如果自己給自己賦值,那就返回自己 }
還可以使用傳值的方法
string& operator=(string s) { swap(_str, s._str); return *this; }
String的析構(gòu)函數(shù)模擬
~string() { if (_str) { delete[] _str; _str = nullptr; } }
補(bǔ)全上述的成員函數(shù)
//因?yàn)閟td庫里原本有一個(gè)string,所以這里加上一個(gè)命名空間,防止命名污染 namespace YDY { class string { public: string(const char* str = "") :_size(strlen(str)) ,_capacity(_size) { _str = new char[_capacity + 1]; //要多給一個(gè)'\0'的空間 strcpy(_str, str); } string(const string& s) :_str(nullptr) ,_size(s._size) ,_capacity(s._capacity) { string tmp(s._str); swap(_str, tmp._str); } string& operator=(const string& s) { if (this != &s) { char* tmp = new char[strlen(s._str) + 1]; strcpy(tmp, s._str); delete[] _str; _str = tmp; _size = s._size; _capacity = s._capacity; } return *this; } ~string() { if (_str) { delete[] _str; _str = nullptr; } _size = _capacity = 0; } private: char* _str; int _size; int _capacity; }; void test() { string s1; string s2(s1); string s3 = s1; } }
迭代器的簡(jiǎn)單模擬
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; }
其他成員函數(shù)的模擬
const char* c_str() { return _str; } size_t size() { return _size; } char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; } const char& operator[](size_t pos) const { assert(pos < _size); return _str[pos]; } //reserve void reserve(size_t n) { if (n > _capacity) { //擴(kuò)容到n+1 //tmp是內(nèi)置類型, char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } // void push_back(char c) { //空間不夠,擴(kuò)容 if (_size == _capacity) { //擴(kuò)容 reserve(_size + 1); } _str[_size] = c; _size++; _str[_size] = '\0'; } void append(const char* str) { int 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) { //復(fù)用追加函數(shù)append() append(str); return *this; } //任意位置的插入 string& insert(size_t pos, char ch) { if (_size == _capacity) { reserve(_size + 1); } //開始插入 int end = _size + 1; //找到pos的位置,并留出pos的位置以便插入 while (end > pos) { _str[end] = _str[end - 1]; end--; } _str[pos] = ch; _size++; return *this; } string& insert(size_t pos, const char* str) { assert(pos < _size); size_t len = strlen(str); if (_size + len > _capacity) { //增容 reserve(_size + len); } //找到pos的位置,并且留出要插入的位置 size_t end = _size + len; while (end > pos) { _str[end] = _str[end - len]; end--; } //開始插入 strncpy(_str + pos, str, len); return *this; } //從pos的位置開始刪除len的長(zhǎng)度 string& erase(size_t pos = 0, size_t len = std::string::npos) { assert(pos < _size); if (len == std::string::npos || pos + len > _size) { _str[pos] = '\0'; _size = pos; } else { strcpy(_str + pos, _str + pos + len); _size -= len; } return *this; }
到此這篇關(guān)于C++ String部分成員模擬實(shí)現(xiàn)流程詳解的文章就介紹到這了,更多相關(guān)C++ String成員模擬實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++字符數(shù)組的輸入輸出和字符串結(jié)束標(biāo)志使用講解
這篇文章主要介紹了C++字符數(shù)組的輸入輸出和符串結(jié)束標(biāo)志使用講解,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09C++簡(jiǎn)單實(shí)現(xiàn)Dijkstra算法
這篇文章主要為大家詳細(xì)介紹了C++簡(jiǎn)單實(shí)現(xiàn)Dijkstra算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05C++使用WideCharToMultiByte函數(shù)生成UTF-8編碼文件的方法
用來映射Unicode字符串的WideCharToMultiByte函數(shù)經(jīng)常被用來進(jìn)行UTF-8編碼的轉(zhuǎn)換,以下我們將看到C++使用WideCharToMultiByte函數(shù)生成UTF-8編碼文件的方法,首先先來對(duì)WideCharToMultiByte作一個(gè)詳細(xì)的了解:2016-06-06