首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ string 類模擬實現:從核心原理到關鍵函數詳解

     編輯:關於C++

C++ 標準庫中的 std::string 提供了豐富的字符串操作功能,底層封裝了動態內存管理、容量擴展、拷貝控制等核心機制。為了深入理解其運作原理,本文將手把手帶你從零開始模擬實現一個簡易的 String 類,涵蓋構造/析構、賦值運算符、下標訪問、尾部追加、插入操作等核心功能。

一、類的整體設計與數據成員

模擬 std::string 的第一步是確定核心數據成員。我們需要一個字符指針 _str 指向動態分配的字符數組,以及兩個整型成員 _size(當前有效字符長度)和 _capacity(當前分配的總容量,含結尾的 \0)。

#include <iostream>
#include <cstring>
using namespace std;

class String {
    friend ostream& operator<<(ostream& os, const String& s);

public:
    // 構造函數:支持默認構造和 C 風格字符串構造
    String(const char* str = "")
        : _size(strlen(str))
        , _capacity(strlen(str) + 1)
        , _str(new char[_capacity]) {
        strcpy(_str, str);
        cout << "String(const char* str)" << endl;
    }

    // 拷貝構造函數
    String(const String& s)
        : _size(s._size)
        , _capacity(s._capacity)
        , _str(new char[_capacity]) {
        strcpy(_str, s._str);
        cout << "String(const String&)" << endl;
    }

    // 析構函數
    ~String() {
        delete[] _str;
        _str = nullptr;
        _size = _capacity = 0;
        cout << "~String()" << endl;
    }

    // 運算符重載聲明
    String& operator=(const String& s);
    char& operator[](size_t index);
    const char& operator[](size_t index) const;

    // 核心功能函數
    void PushBack(char c);
    String& operator+=(const String& str);
    String& operator+=(const char* s);
    String& operator+=(char c);

    // insert 多載族
    String& insert(size_t pos, const String& str);
    String& insert(size_t pos, const String& str, size_t subPos, size_t n);
    String& insert(size_t pos, const char* s, size_t n);
    String& insert(size_t pos, const char* s);
    String& insert(size_t pos, size_t n, char c);

private:
    // 容量檢查與擴容(私有,內部自動調用)
    void CheckCapacity(size_t count);

    char* _str;      // 動態字符數組
    size_t _size;    // 有效字符長度
    size_t _capacity;// 總容量
};

二、核心輔助函數:容量檢查與擴容

CheckCapacity 是所有修改性操作的基石。當現有容量不足以容納新增字符時,按 2 倍策略或按需分配更大空間,並將舊數據拷貝至新內存。

void String::CheckCapacity(size_t count) {
    if (_size + count >= _capacity) {
        size_t newCapacity = max(2 * _capacity, _capacity + count);
        char* tmp = new char[newCapacity];
        strcpy(tmp, _str);
        delete[] _str;
        _str = tmp;
        _capacity = newCapacity;
    }
}

三、賦值運算符重載:深拷貝與 Copy-and-Swap

賦值運算符必須處理自我賦值、釋放舊內存、深拷貝新數據。這裡展示兩種經典實現:

1. 傳統深拷貝實現

String& String::operator=(const String& s) {
    if (this != &s) { // 防止自我賦值
        delete[] _str;
        _str = new char[strlen(s._str) + 1];
        strcpy(_str, s._str);
        _size = s._size;
        _capacity = s._capacity;
    }
    return *this;
}

2. Copy-and-Swap 惯用法(推薦)

利用拷貝構造函數創建臨時對象,再交換內部指針,代碼簡潔且異常安全。

String& String::operator=(String s) { // 參數按值傳遞,自動調用拷貝構造
    swap(_str, s._str);
    swap(_size, s._size);
    swap(_capacity, s._capacity);
    return *this; // 臨時對象 s 析構時釋放舊內存
}

四、下標訪問運算符 operator[]

返回字符引用,支持讀寫。注意區分 const 與非 const 版本。

char& String::operator[](size_t index) {
    return _str[index];
}
const char& String::operator[](size_t index) const {
    return _str[index];
}

五、尾部追加:PushBack 與 operator+=

PushBack 單字符追加,內部調用 CheckCapacity(1) 確保空間。operator+= 提供三種重載,分別處理 String、C 字符串、單字符,核心邏輯均為:擴容 → strcat 或直接賦值 → 更新 _size → 補 \0。

void String::PushBack(char c) {
    CheckCapacity(1);
    _str[_size++] = c;
    _str[_size] = '\0';
}

String& String::operator+=(const String& str) {
    CheckCapacity(str._size);
    strcat(_str, str._str);
    _size += str._size;
    return *this;
}

String& String::operator+=(const char* s) {
    size_t len = strlen(s);
    CheckCapacity(len);
    strcat(_str, s);
    _size += len;
    return *this;
}

String& String::operator+=(char c) {
    CheckCapacity(1);
    _str[_size++] = c;
    _str[_size] = '\0';
    return *this;
}

六、插入操作 insert 族函數詳解

insert 的核心難點在於「在指定位置騰出空間並拼接字符串」。所有重載統一採用「臨時緩衝區保存尾部 → 截斷原字符串 → 追加新內容 → 拼回尾部」的策略。

1. 插入 String 對象

String& String::insert(size_t pos, const String& str) {
    if (pos > _size) return *this; // 位置非法直接返回
    CheckCapacity(str._size);
    char* tmp = new char[_size - pos + 1];
    strcpy(tmp, _str + pos);       // 保存 pos 及之後的內容
    _str[pos] = '\0';              // 截斷
    strcat(_str, str._str);        // 追加新串
    strcat(_str, tmp);             // 拼回尾部
    _size += str._size;
    _str[_size] = '\0';
    delete[] tmp;
    return *this;
}

2. 插入 String 的子串

String& String::insert(size_t pos, const String& str, size_t subPos, size_t n) {
    if (pos > _size || subPos > str._size || n > str._size - subPos) return *this;
    CheckCapacity(n);
    char* tmp = new char[_size - pos + 1];
    strcpy(tmp, _str + pos);
    _str[pos] = '\0';
    strncat(_str, str._str + subPos, n);
    strcat(_str, tmp);
    _size += n;
    _str[_size] = '\0';
    delete[] tmp;
    return *this;
}

3. 插入 C 字符串前 n 字符

String& String::insert(size_t pos, const char* s, size_t n) {
    if (pos > _size) return *this;
    CheckCapacity(n);
    char* tmp = new char[_size - pos + 1];
    strcpy(tmp, _str + pos);
    _str[pos] = '\0';
    strncat(_str, s, n);
    strcat(_str, tmp);
    _size += n;
    _str[_size] = '\0';
    delete[] tmp;
    return *this;
}

4. 插入整個 C 字符串

String& String::insert(size_t pos, const char* s) {
    return insert(pos, s, strlen(s)); // 復用上一個重載
}

5. 插入 n 個相同字符

String& String::insert(size_t pos, size_t n, char c) {
    if (pos > _size) return *this;
    CheckCapacity(n);
    char* tmp = new char[_size - pos + 1];
    strcpy(tmp, _str + pos);
    _str[pos] = '\0';
    for (size_t i = 0; i < n; ++i) _str[_size + i] = c;
    _size += n;
    _str[_size] = '\0';
    strcat(_str, tmp);
    delete[] tmp;
    return *this;
}

七、輸出流運算符重載

ostream& operator<<(ostream& os, const String& s) {
    os << s._str;
    return os;
}

八、總結與最佳實踐

  • 資源管理:嚴格遵循 RAII,構造獲取資源,析構釋放資源。
  • 異常安全:推薦使用 Copy-and-Swap 實現賦值運算符,提供強異常安全保證。
  • 擴容策略:採用 2 倍增長平衡時間與空間效率,避免頻繁分配。
  • const 正確性:為讀寫操作分別提供 const 與非 const 重載。
  • 代碼復用:insert 族函數盡量相互調用,減少重複邏輯。

通過這個模擬實現,你應該能清晰掌握 std::string 底層的動態內存管理、容量增長、拷貝控制語義以及各類修改操作的核心邏輯。實際工程中請直接使用標準庫 std::string,它經過高度優化並處理了大量邊界情況。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved