網(wǎng)站首頁 編程語言 正文
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ì)成功,如果一開始就給釋放了,而我去申請空間卻申請不到,那就是不僅沒有賦值成功,還把我自己原本有的給丟了。
//正確的寫法 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; } }
迭代器的簡單模擬
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的長度 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; }
原文鏈接:https://blog.csdn.net/qq_56870066/article/details/124145422
相關(guān)推薦
- 2022-09-08 pytorch實(shí)現(xiàn)加載保存查看checkpoint文件_python
- 2023-10-12 react報(bào)錯(cuò):Can’t perform a React state update on an u
- 2022-07-01 Oracle的約束介紹與約束維護(hù)_oracle
- 2022-05-27 五個(gè)經(jīng)典鏈表OJ題帶你進(jìn)階C++鏈表篇_C 語言
- 2023-01-03 Qt學(xué)習(xí)之容器類的使用教程詳解_C 語言
- 2023-02-07 C#實(shí)現(xiàn)加密bat文件的示例詳解_C#教程
- 2022-06-06 webpack5.6.0解決報(bào)The ‘mode‘ option has not been set,
- 2022-12-01 sqlserver數(shù)據(jù)庫導(dǎo)入方法的詳細(xì)圖文教程_MsSql
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支