C++ 中 string 類的解析及簡易自我實現

目錄

引言

標準庫中的?string?類

功能概述

常見操作示例

自我實現簡易?string?類

代碼結構概述

1.?String11.h?頭文件

?類的成員變量

迭代器相關?

構造函數和析構函數?

?基本訪問和修改方法

賦值運算符重載?

內存管理和擴容?

以下代碼在.cpp文件中解析:?

?2.?String11.cpp?實現文件

字符串修改操作

插入和刪除操作?

?查找和截取操作

比較運算符重載?

輸入輸出運算符重載

3.?Teststring.cpp?測試文件?

?

主要功能點

4.特色總結?

總結


引言

在 C++ 編程中,string?類是一個非常常用且重要的類,它位于標準庫?<string>?中,為我們處理字符串提供了便捷的方式。不過,為了更好地理解?string?類的工作原理,我們可以嘗試自己實現一個簡易的?string?類。本文將詳細解析 C++ 中的?string?類,并結合提供的代碼文件,介紹如何自我實現一個簡易的?string?類。

標準庫中的?string?類

功能概述

C++ 標準庫中的?string?類是一個模板類?std::basic_string<char>?的特化版本,它封裝了字符數組,提供了一系列操作字符串的方法,如字符串的拼接、查找、替換、插入、刪除等。使用?string?類,我們可以避免手動管理內存,減少內存泄漏的風險。

常見操作示例

#include <iostream>
#include <string>int main() {std::string s1 = "Hello";std::string s2 = " World";std::string s3 = s1 + s2; // 字符串拼接std::cout << s3 << std::endl;size_t pos = s3.find("World"); // 查找子字符串if (pos != std::string::npos) {std::cout << "Found at position: " << pos << std::endl;}s3.insert(5, ","); // 插入字符std::cout << s3 << std::endl;return 0;
}

自我實現簡易?string?類

代碼結構概述

提供的代碼文件包含了三個主要部分:String11.h?頭文件、String11.cpp?實現文件和?Teststring.cpp?測試文件。下面我們將詳細分析每個部分。

1.?String11.h?頭文件

一些短小且常用的函數都可以直接在頭文件內實現,調用時直接內聯展開。

?類的成員變量
private:char* _str = nullptr;size_t _size;size_t _capacity;static const size_t npos;
  • _str:一個指向字符數組的指針,用于存儲字符串的實際內容。
  • _size:表示當前字符串的長度,即字符串中字符的個數(不包括字符串結束符?'\0')。
  • _capacity:表示當前分配給字符串的內存容量,即?_str?指向的字符數組的大小(包括字符串結束符?'\0')。
  • npos:一個靜態常量,表示無效的位置,通常用于表示查找操作未找到目標時的返回值。
迭代器相關?
public: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;}
  • 功能:定義了迭代器類型?iterator?和?const_iterator,并提供了?begin()?和?end()?方法,使得該?string?類可以像標準容器一樣使用迭代器進行遍歷。
  • 特點:支持范圍?for?循環和其他基于迭代器的算法,增強了代碼的通用性和可維護性。
構造函數和析構函數?
string(const char* str = "")
{_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);
}string(const string& s)
{_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;
}~string()
{delete[] _str;_str = nullptr;_size = _capacity = 0;
}
  • 默認構造函數:接受一個 C 風格字符串作為參數,若未提供則默認為空字符串。分配足夠的內存來存儲字符串,并將其復制到?_str?中。
  • 拷貝構造函數:接受一個?string?對象作為參數,創建一個新的?string?對象,其內容和容量與原對象相同。
  • 析構函數:釋放?_str?指向的動態分配內存,避免內存泄漏,并將?_size?和?_capacity?置為 0。
?基本訪問和修改方法
const char* c_str() const
{return _str;
}void clear()
{_str[0] = '\0';_size = 0;
}const size_t size() const
{return _size;
}const size_t capacity() const
{return _capacity;
}char& operator[](size_t pos)
{assert(pos < _size);return _str[pos];
}const char& operator[](size_t pos) const
{assert(pos < _size);return _str[pos];
}
  • c_str():返回指向字符串實際內容的 C 風格字符串指針。
  • clear():清空字符串,將字符串的第一個字符置為?'\0',并將?_size?置為 0。
  • size():返回字符串的當前長度。
  • capacity():返回字符串當前分配的內存容量。
  • operator[]:重載了下標運算符,允許通過下標訪問字符串中的字符。提供了常量和非常量版本,以支持對常量和非常量對象的訪問。
賦值運算符重載?
string& operator=(const string& s)
{if(this != &s){delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;
}
  • 功能:實現了對象之間的賦值操作。如果目標對象和源對象不是同一個對象,釋放目標對象的原有內存,分配新的內存并復制源對象的內容。
  • 特點:使用了自我賦值檢查,避免了不必要的內存釋放和重新分配。
內存管理和擴容?
void reserve(size_t n)
{cout << "reserve:" << n << endl;if(n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}
}
  • 功能:預留至少?n?個字符的內存空間。如果?n?大于當前容量,則分配新的內存,將原字符串復制到新內存中,并釋放原內存。
  • 特點:避免了頻繁的內存重新分配,提高了性能。
以下代碼在.cpp文件中解析:?
void push_back(char ch);
void append(const char* str);
string& operator+=(char ch);
string& operator+=(const char* str);
void insert(size_t pos, char ch);
void insert(size_t pos, const char* str);
void erase(size_t pos, size_t len = npos);
size_t find(char ch, size_t pos = 0);
size_t find(const char* str, size_t pos = 0);
string substr(size_t pos = 0, size_t len = npos);
bool operator<(const string& s1, const string& s2);
bool operator<=(const string& s1, const string& s2);
bool operator>(const string& s1, const string& s2);
bool operator>=(const string& s1, const string& s2);
bool operator==(const string& s1, const string& s2);
bool operator!=(const string& s1, const string& s2);
istream& getline(istream& in, string& s);
ostream& operator<<(ostream& out, const string& s);
istream& operator>>(istream& in, string& s);

?2.?String11.cpp?實現文件

先給定static變量npos值:

const size_t string::npos = -1;

?接下來實現剩下的代碼:

字符串修改操作
void string::push_back(char ch){if(_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';}void string::append(const char* str){size_t len = strlen(str);if(len + _size > _capacity){// 大于2倍,需要多少開多少,小于2倍按2倍擴reserve(len + _size > _capacity * 2 ? len + _size : _capacity * 2);}strcpy(_str + _size, str);_size = len;}string& string::operator+=(char ch){push_back(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}
  • push_back(char ch):在字符串末尾添加一個字符。如果當前容量不足,則進行擴容。
  • append(const char* str):在字符串末尾添加一個 C 風格字符串。如果需要,會進行擴容。
  • operator+=(char ch)?和?operator+=(const char* str):重載了?+=?運算符,分別用于添加單個字符和 C 風格字符串,調用?push_back?和?append?方法實現。
插入和刪除操作?
 void string::insert(size_t pos, char ch){assert(pos <= _size);if(_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}size_t end =  _size + 1;while(end > pos){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;}void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if(len + _size > _capacity){reserve(len + _size > 2 * _capacity ? len + _size : _capacity * 2);}size_t end = _size + len;while(end > pos + len - 1){_str[end] = _str[end - len];end--;}for(size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;}void string::erase(size_t pos, size_t len){assert(_size > pos);if(len >= _size - pos) // 不能寫pos + len , 因為len == npos時為INT_MAX越界{_size = pos;_str[pos] = '\0';}else{size_t res = pos + len;while(res <= _size){_str[pos++] = _str[res++];}_size -= len;}}
  • insert(size_t pos, char ch):在指定位置?pos?插入一個字符。如果容量不足,會進行擴容。
  • insert(size_t pos, const char* str):在指定位置?pos?插入一個 C 風格字符串。同樣,若需要會進行擴容。
  • erase(size_t pos, size_t len = npos):從指定位置?pos?開始刪除?len?個字符。如果?len?大于等于從?pos?到字符串末尾的字符數,則刪除從?pos?開始的所有字符。
?查找和截取操作
size_t string::find(char ch, size_t pos){assert(pos < _size);for(size_t i = pos; i < _size; i++){if(_str[i] == ch)return i;}return npos;}size_t string::find(const char* str, size_t pos){assert(pos < _size);const char* res = strstr(_str + pos, str);if(res == nullptr){return npos;}return res - _str;}string string::substr(size_t pos, size_t len){assert(pos < _size);//len大于字符串長度,更新一下lenif(len > _size - pos){len = _size - pos;}string sub;sub.reserve(len);for(size_t i = 0; i < len; i++){sub += _str[i + pos];}return sub;}
  • find(char ch, size_t pos = 0):從指定位置?pos?開始查找字符?ch,返回其第一次出現的位置。如果未找到,則返回?npos
  • find(const char* str, size_t pos = 0):從指定位置?pos?開始查找 C 風格字符串?str,返回其第一次出現的位置。若未找到,返回?npos
  • substr(size_t pos = 0, size_t len = npos):從指定位置?pos?開始截取長度為?len?的子字符串。如果?len?大于從?pos?到字符串末尾的字符數,則截取到字符串末尾。
比較運算符重載?
bool operator<(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) < 0;}bool operator<=(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) <= 0;}bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}bool operator==(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) == 0;}bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}
  • 功能:重載了比較運算符,用于比較兩個?string?對象的大小。使用?strcmp?函數進行比較。
  • 特點:使得?string?對象可以像標準類型一樣進行比較,方便進行排序和條件判斷。
輸入輸出運算符重載
ostream& operator<<(ostream& out, const string& s){for(auto ch : s){out << ch;}return out;}// istream& operator>>(istream& in, string& s)// {//     s.clear();//     char ch;//     ch = in.get();//     while(ch != ' ' && ch != '\n')//     {//         s += ch;//         ch = in.get();//     }//     return in;// }優化istreamistream& operator>>(istream& in, string& s){s.clear();const int N = 256;char buff[N];int i = 0;char ch;ch = in.get();while(ch != ' ' && ch != '\n'){buff[i++] = ch;if(i == N - 1){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if(i > 0){buff[i] = '\0';s += buff;}return in;}istream& getline(istream& in, string& s){s.clear();const int N = 256;char buff[N];int i = 0;char ch;ch = in.get();while(ch != '\n'){buff[i++] = ch;if(i == N - 1){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if(i > 0){buff[i] = '\0';s += buff;}return in;}
  • getline(istream& in, string& s):從輸入流中讀取一行字符串,直到遇到換行符?'\n',并將其存儲到?s?中。
  • operator<<(ostream& out, const string& s):重載了輸出運算符,將?string?對象的內容輸出到輸出流中。
  • operator>>(istream& in, string& s):重載了輸入運算符,從輸入流中讀取一個單詞(以空格或換行符分隔),并將其存儲到?s?中。

3.?Teststring.cpp?測試文件?

?

#include "String11.h"namespace lmr
{void string_test(){string s("haha");cout << s.c_str() << endl;s += "sss";s += 's';cout << s.c_str() << endl;cout << s.size() << " " << s.capacity() <<  endl;s.insert(2, "sss");cout << s.c_str() << endl;s.insert(5, '*');cout << s.c_str() << endl;s.erase(2);cout << s.c_str() << endl;string s1("test.cpp");size_t pos = s1.find('.');string buffix = s1.substr(pos);cout << buffix.c_str() << endl;   }void string_test1(){string s("Hello World");string s2(s);bool sign = s2 == s;if(sign == true){// cin >> s;getline(cin, s);cout << s << endl;string s3;cin >> s3;cout << s3 << endl;}cout << endl;}}int main()
{lmr::string_test1();return 0;
}
主要功能點
  • 測試用例:提供了多個測試用例,測試了字符串的拼接、插入、刪除、查找、截取等操作。

4.特色總結?

  1. 動態內存管理:通過?new?和?delete?運算符動態分配和釋放內存,避免了固定大小數組的限制。
  2. 模擬標準庫接口:提供了與?std::string?類似的接口,如迭代器、構造函數、賦值運算符等,方便用戶使用。
  3. 內存優化:使用?reserve?方法進行內存預分配,減少了頻繁的內存重新分配,提高了性能。
  4. 異常處理:使用?assert?進行邊界檢查,確保操作的安全性。但在實際應用中,建議使用更健壯的異常處理機制。
  5. 可擴展性:可以方便地添加更多的功能,如替換、大小寫轉換等。

總結

通過自我實現一個簡易的?string?類,我們可以更深入地理解 C++ 中?string?類的工作原理和內存管理機制。同時,我們也學習了如何使用類和對象的概念,以及如何重載運算符和使用迭代器。在實際編程中,建議使用標準庫中的?string?類,因為它經過了嚴格的測試和優化,具有更高的性能和可靠性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87983.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87983.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87983.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

計算機的性能指標(選擇題0~1題無大題)

存儲器的性能指標 總容量存儲單元個數*存儲字長 bit 例&#xff1a;MAR16位&#xff0c;MDR16位 總容量2的16次方*16bit 補充&#xff1a; n個二進制位就有2的n次方不同的狀態 一般描述文件大小容量單位 2的10次方&#xff1a;K 2的20次方&#xff1a;M 2的…

React 核心原理與Fiber架構

目錄 一、虛擬 DOM 二、Diffing 算法 三、Fiber 架構 四、渲染流程 1. Render 階段&#xff08;可中斷異步過程&#xff09; 2. Commit 階段&#xff08;同步不可中斷&#xff09; 五、時間切片&#xff08;Time Slicing&#xff09; 六、核心流程步驟總結 1. 狀態更新…

【破局痛點,賦能未來】領碼 SPARK:鑄就企業業務永續進化的智慧引擎—— 深度剖析持續演進之道,引領數字化新范式

摘要 在瞬息萬變的數字時代&#xff0c;企業對業務連續性、敏捷創新及高效運營的需求日益迫切。領碼 SPARK 融合平臺&#xff0c;秉持“持續演進”這一核心理念&#xff0c;以 iPaaS 與 aPaaS 為雙擎驅動&#xff0c;深度融合元數據驅動、智能端口調度、自動化灰度切換、AI 智…

掌握C++核心特性

目標&#xff1a; 掌握C核心特性&#xff0c;為嵌入式開發打基礎 好的&#xff0c;我來為你詳細梳理一下 繼承與多態、虛函數 相關的知識點&#xff0c;包括單繼承、多繼承、虛函數表機制、純虛函數與抽象類、動態綁定。以下內容適合中等難度層次的理解&#xff0c;便于考試復…

python的高校教師資源管理系統

目錄 技術棧介紹具體實現截圖系統設計研究方法&#xff1a;設計步驟設計流程核心代碼部分展示研究方法詳細視頻演示試驗方案論文大綱源碼獲取/詳細視頻演示 技術棧介紹 Django-SpringBoot-php-Node.js-flask 本課題的研究方法和研究步驟基本合理&#xff0c;難度適中&#xf…

Java Collections工具類:高效集合操作

Collections工具類概述 Collections是Java提供的集合操作工具類&#xff0c;位于java.util包中&#xff0c;包含大量靜態方法&#xff0c;用于對List、Set、Map等集合進行排序、查找、替換、同步化等操作。 常用方法及代碼示例 排序操作 sort(List<T> list)&#xff1a…

vue指令總結

vue指令總結 一、總述 二、代碼實現&#xff08;內含大量注釋&#xff09; <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>vue入門</title><!-- 使用Vue 3官方CDN --><script src"https://unpkg.c…

RUP——統一軟件開發過程

RUP概述 RUP&#xff08;Rational Unified Process&#xff09;&#xff0c;統一軟件開發過程&#xff0c;統一軟件過程是一個面向對象且基于網絡的程序開發方法論。 在RUP中采用“41”視圖模型來描述軟件系統的體系結構。“41”視圖包括邏輯視圖、實現視圖、進程視圖、部署視…

SpringBoot電腦商城項目--增加減少購物車商品數量

1. 持久層 1.1 規劃sql語句 執行更新t_cart表記錄的num值根據cid查詢購物車的數據是否存在 select * from t_cart where cid#{cid} 1.2 接口和抽象方法 /*** 獲取購物車中商品的數據總數* return 購物車中商品的數據總數*/Cart findByCid(Integer cid); 1.3 xml文件中sql映射…

零基礎學習Redis(13) -- Java使用Redis命令

上期我們學習了如何使用Java連接到redis&#xff0c;這期我們來學習如何在java中使用redis中的一些命令 1. set/get 可以看到jedis類中提供了很多set方法 public static void test1(Jedis jedis) {jedis.flushAll();jedis.set("key1", "v1");jedis.set(&q…

解決OSS存儲桶未創建導致的XML錯誤

前言 在Java開發中&#xff0c;集成對象存儲服務&#xff08;OSS&#xff09;時&#xff0c;開發者常會遇到一個令人困惑的錯誤提示&#xff1a; “This XML file does not appear to have any style information associated with it. The document tree is shown below.” 此…

Spring 表達式語言(SpEL)深度解析:從基礎到高級實戰指南

目錄 一、SpEL是什么&#xff1f;為什么需要它&#xff1f; 核心價值&#xff1a; 典型應用場景&#xff1a; 二、基礎語法快速入門 1. 表達式解析基礎 2. 字面量表示 3. 屬性訪問 三、SpEL核心特性詳解 1. 集合操作 2. 方法調用 3. 運算符大全 4. 類型操作 四、Sp…

算法導論第二十四章 深度學習前沿:從序列建模到創造式AI

第二十四章 深度學習前沿&#xff1a;從序列建模到創造式AI 算法的進化正在重新定義人工智能的邊界 深度學習作為機器學習領域最活躍的分支&#xff0c;正以驚人的速度推動著人工智能的發展。本章將深入探討五大前沿方向&#xff0c;通過原理分析、代碼實現和應用場景展示&…

抽象工廠設計模式

1.問題背景&#xff1a; 現在有兩個產品(Product)分別是手機殼(PhoneCase)和耳機(EarPhone)&#xff0c;但是他們會來自于各個生產廠商&#xff0c;比如說Apple和Android等等 那么至少會有四個產品&#xff0c;分別是安卓手機殼&#xff0c;安卓耳機&#xff0c;蘋果手機殼&a…

GESP 3級 C++ 知識點總結

根據GESP考試大綱 (2024年3月版)&#xff0c;幫大家總結一下GESP 3級 C語言的知識點&#xff1a; 核心目標&#xff1a; 掌握C程序的基本結構&#xff0c;理解并能運用基礎的編程概念解決稍復雜的問題&#xff0c;重點是函數、一維數組和字符串處理。 主要知識點模塊&#x…

騰訊云主動型云蜜罐技術解析:云原生威脅狩獵的革新實踐(基于騰訊云開發者社區技術網頁與行業實踐)

摘要 騰訊云主動型云蜜罐&#xff08;Active Cloud Honeypot&#xff09;通過動態誘捕機制和云原生架構&#xff0c;在威脅檢測效率、攻擊鏈還原深度、防御聯動實時性等維度實現突破。相較于傳統蜜罐&#xff0c;其核心優勢體現在&#xff1a; 部署效率&#xff1a;分鐘級完成…

企業微信wecom/jssdk的使用(入門)

概述 記錄一個企業微信jssdk的使用&#xff0c;因為要用到圖片上傳、掃描二維碼等工具。項目是uniapp開發的h5項目&#xff0c;fastadmin&#xff08;thinkphp5&#xff09;后端 先看官方文檔 https://developer.work.weixin.qq.com/document/path/90547#%E5%BA%94%E7%94%A8…

大零售生態下開源鏈動2+1模式、AI智能名片與S2B2C商城小程序的協同創新研究

摘要&#xff1a;在流量紅利消退、零售形態多元化的背景下&#xff0c;大零售生態成為商業發展的新趨勢。本文聚焦開源鏈動21模式、AI智能名片與S2B2C商城小程序在零售領域的協同應用&#xff0c;探討其如何打破傳統零售邊界&#xff0c;實現流量變現與用戶資產化。研究表明&am…

Scrapy全流程(一)

創建一個scrapy項目:scrapy startproject mySpider 生成一個爬蟲:scrapy genspider douban movie.douban.com 提取數據:完善spider&#xff0c;使用xpath等方法 保存數據:pipeline中保存數據 2 創建scrapy項目 下面以抓取豆瓣top250來學習scrapy的入門使用&#xff1a;豆瓣…

【Elasticsearch】TF-IDF 和 BM25相似性算法

在 Elasticsearch 中&#xff0c;TF-IDF 和 BM25 是兩種常用的文本相似性評分算法&#xff0c;但它們的實現和應用場景有所不同。以下是對這兩種算法的對比以及在 Elasticsearch 中的使用情況&#xff1a; TF-IDF - 定義與原理&#xff1a;TF-IDF 是一種經典的信息檢索算法&am…