自實現string類

来源:https://www.cnblogs.com/zhe666/archive/2023/11/27/17859827.html
-Advertisement-
Play Games

1 簡介 Spring Data Redis是 Spring Data 系列的一部分,它提供了Spring應用程式對Redis的輕鬆配置和使用。它不僅提供了對Redis操作的高級抽象,還支持Jedis和Lettuce兩種連接方式。 可通過簡單的配置就能連接Redis,並且可以切換Jedis和Lett ...


一. 環境

Linux x86_64,g++ 8.5.0

二. 實現

自實現 string 之前一直想寫來著,一直拖著,現在把它完稿。這個版本是比較簡單的版本,有一些可能有不同的或者更好的實現方式,後面有機會會加到裡面。

打算實現的介面如下

class MyString
{
    friend std::ostream & operator<<(std::ostream & co, const MyString &ms);
    friend std::istream & operator>>(std::istream & ci, MyString &ms);
public:
    MyString(const char * s = nullptr);
    ~MyString();
    MyString(const MyString & another);
    MyString & operator=(const MyString & another);

    MyString operator+(const MyString & another);
    MyString & operator+=(const MyString & another);
    bool operator>(const MyString & another);
    bool operator<(const MyString & another);
    bool operator==(const MyString & another);
    char & operator[](int n);
    char & at(int n);
private:
    char * m_str;
};
  1. 構造函數,參數使用預設參數,預設參數作標記位。不論是否傳遞實參,申請資源時均以數組形式申請。不傳遞實參時,申請一個 char 的數組,有傳遞實參時,以實際的為準。這樣,在釋放資源時,均可以 delete []m_str 形式釋放。
MyString::MyString(const char *str)
{
    if (nullptr == str)
    {
        m_str = new char[1];
        *m_str = '\0';
    }
    else
    {
        m_str = new char[strlen(str)+1];
        strcpy(m_str, str);
    }
}
  1. 拷貝賦值,使用了兩種方式。

第一種是基礎的寫法,先 delete 堆上的空間,再申請新的空間,然後複製內容。需要註意的是,需判斷是否是自賦值的情況。

第二種採用了 copy && swap 技術,相對完善一點,前一種方式,在 delete []m_str 後如果程式出現異常,此時其它地方有使用到 m_str 的話就尷尬了,而後一種方式就沒有這個問題。

// version1
/*
MyString & MyString::operator=(const MyString &another)
{
    if (this == &another)
    {
        return *this;
    }

    delete []m_str;
    int len = strlen(another.m_str);
    m_str = new char[len+1];
    strcpy(m_str, another.m_str);

    return *this;
}
*/

// version2,採用 copy and swap 技術
MyString & MyString::operator=(const MyString &another)
{
    if (this == &another)
    {
        return *this;
    }

    MyString ms(another);
    std::swap(this->m_str, ms.m_str);

    return *this;
}
  1. 重載 + 運算符,成員函數返回一個臨時對象。在申請新的空間後,在使用 strcat() 之前需要初始化,否則可能會出現問題。strcat() 是從末尾為 '\0' 的地方開始拼接的。
MyString MyString::operator+(const MyString &another)
{
    MyString ms;

    int len = strlen(this->m_str) + strlen(another.m_str);
    delete []ms.m_str;
    ms.m_str = new char[len +1]{0};  // 註意初始化
    strcat(strcat(ms.m_str, this->m_str), another.m_str);

    return ms;
}
  1. 重載 += 運算符,返回值類型是引用類型,這樣可以連續使用 +=

使用 realloc() 後,在使用 strcat() 連接兩個字元串之前,需要將 m_str 後面一部分新擴充的空間進行初始化。

MyString & MyString::operator+=(const MyString &another)
{
    int lenOfSource = strlen(this->m_str);
    int lenOfAnother = strlen(another.m_str);
    this->m_str = (char *)realloc(this->m_str, lenOfSource+lenOfAnother+1);
    memset(this->m_str+lenOfSource, 0, lenOfAnother+1);
    strcat(this->m_str, another.m_str);

    return *this;
}
  1. 重載 > 運算符
bool MyString::operator>(const MyString &another)
{
    return strcmp(this->m_str, another.m_str) > 0;
}

重載 <== 與上面類似,就不重覆列舉了。

  1. 重載 [] 運算符,這個沒啥好說的了。
char & MyString::operator[](int n)
{
    return m_str[n];
}
  1. 成員函數 at()
char & MyString::at(int n)
{
    return m_str[n];
}
  1. 重載輸出 << 和 輸入 >> 運算符。

在測試成員函數前,可以早點寫這兩個函數,測試時就方便列印了,不然還需要單獨添加一個成員函數返回 m_str 了。

重載運算符,目標形式是:

Mystring ms;
cout << ms; 
cin >> ms;

對於重載,一般會考慮到成員函數重載和全局重載,但是 ostream 類和 istream 類都是系統提供的類,我們不可能在 ostream 類和 istream 類中進行修改,因此只能放棄成員函數重載。此時,只能是全局重載,即全局函數重載了。

考慮到會連續輸出(cout << a << b;),因此返回類型是 ostream & 類型,它是經入參而來,入參類型也是 ostream &

std::ostream & operator<<(std::ostream & co, const MyString &ms)
{
    co << ms.m_str;
    return co;
}

輸入運算符與輸出運算符類似,第二個入參不能是 const 類型,因為需要修改入參 ms。這裡處理的相對簡單了,棧上申請了1024位元組的字元數組用以存儲輸入的數據,實際上會有不夠用的情況。

std::istream & operator>>(std::istream & ci, MyString &ms)
{
    // 簡單處理,申請一塊固定大小的記憶體
    char ch[1024];
    ci >> ch;
    delete []ms.m_str;
    ms.m_str = new char[strlen(ch)+1];
    strcpy(ms.m_str, ch);
    return ci;
}

三. 完整代碼,可點擊鏈接 mystring ,如有有問題或不到之處,請指出並交流,看到後我會修改。

四. 參考

C++基礎與提高 王桂林


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 如果你想要實現自己的夢想,就必須先擁有勇氣去追求它。 1. React Props 屬性 props 主要解決兩個問題:復用性問題以及可以讓組件之間通信。 屬性 props 正常是外部傳入的,組件內部也可以通過一些方式來初始化的設置,屬性不能被組件自己更改(屬性是描述性質、特點的,組件自己不能隨意更 ...
  • 簡介 本章節從精准定位、分層設計、非同步組件、拖拽四個方面分析飛碼畫布設計。 一、精准定位設計 飛碼畫布是一個套件,可對外提供畫布能力。精准定位有兩種情況,一是目標組件無子組件,而是目標組件有子組件。 無子組件:目標組件分為支持與不支持放子組件兩種情況。 有子組件:滑鼠相對於子組件(目標組件)對角線位 ...
  • 這是一本比較冷門的書《設計規則:模塊化的力量》,雖然豆瓣上只有58個評價,但是確實能學到很多東西。 這本書對我非常深遠。不是是投資,創業,還是其他領域,模塊化思想都能幫上你。這本書告訴我們生萬物的規則。 書籍電子版PDF(建議及時保存,避免被和諧):https://pan.quark.cn/s/aa ...
  • Spring Boot支持多種日誌框架,包括Logback、Log4j2和Java Util Logging(JUL)。在Spring Boot中,可以通過簡單的配置來集成這些熱門的日誌框架。 下麵將詳細說明如何集成Logback、Log4j2和Java Util Logging,並提供相應的源代碼 ...
  • Cameo項目介紹: 1、實時捕獲並顯示攝像頭幀。 2、具備截圖、保存視頻和退出三個功能鍵。 要求存在文件:manager.py 和 cameo.py 一、manager.py 兩個類:CaptureManager、WindowManager CaptureManager負責攝像頭幀的捕獲,編解碼得 ...
  • 題目 給你一個數組 nums 和一個值 val,你需要 原地 移除所有數值等於 val 的元素,並返回移除後數組的新長度。 不要使用額外的數組空間,你必須僅使用 O(1) 額外空間並 原地 修改輸入數組。 元素的順序可以改變。你不需要考慮數組中超出新長度後面的元素。 說明: 為什麼返回數值是整數,但 ...
  • Flask-SocketIO 是基於 Flask 的一個擴展,用於簡化在 Flask 應用中集成 WebSocket 功能。WebSocket 是一種在客戶端和伺服器之間實現實時雙向通信的協議,常用於實現實時性要求較高的應用,如聊天應用、實時通知等,使得開發者可以更輕鬆地構建實時性要求較高的應用。通... ...
  • keycloak可以幫助我們實現這個功能:用戶token每5分鐘失效一次,失效後通過refresh_token來換新的token,而refresh_token每30天失效一次,但如果用戶3天都沒有任何操作(就是沒有用refresh_token去換新的token),那麼3天後也讓refresh_tok ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...