自實現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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...