【C++】string类模拟实现(超详细解析,小白必看系列)

模拟实现 C++ 标准库中的 std::string 类是一个很好的练习,可以帮助深入理解 C++ 的内存管理和面向对象编程。

1 浅拷贝和深拷贝解析

浅拷贝和深拷贝是对象复制中的两种不同机制,理解它们的区别对于编写高效、无误的代码至关重要。

浅拷贝 (Shallow Copy)

浅拷贝是指创建一个新对象,这个新对象有着原始对象属性值的一份精确拷贝。如果属性是基本数据类型,拷贝的就是基本数据类型的值;如果属性是引用类型,拷贝的就是内存地址。因此,浅拷贝后的新对象和原对象共享同一块内存,修改一个对象可能会影响另一个对象。

示例:

#include <iostream>
#include <cstring>

class ShallowCopy {
public:
    ShallowCopy(const char* data) {
        _data = new char[strlen(data) + 1];
        strcpy(_data, data);
    }

    ShallowCopy(const ShallowCopy& other) {
        _data = other._data; // 仅复制指针
    }

    ~ShallowCopy() {
        delete[] _data;
    }

    void print() const {
        std::cout << _data << std::endl;
    }

private:
    char* _data;
};

int main() {
    ShallowCopy obj1("Hello");
    ShallowCopy obj2 = obj1; // 浅拷贝

    obj1.print(); // 输出: Hello
    obj2.print(); // 输出: Hello

    return 0;
}

深拷贝 (Deep Copy)

深拷贝是指创建一个新对象,并递归地复制所有对象的属性。新的对象与原始对象没有任何关联,修改一个对象不会影响另一个对象。

示例:

#include <iostream>
#include <cstring>

class DeepCopy {
public:
    DeepCopy(const char* data) {
        _data = new char[strlen(data) + 1];
        strcpy(_data, data);
    }

    DeepCopy(const DeepCopy& other) {
        _data = new char[strlen(other._data) + 1];
        strcpy(_data, other._data); // 复制内容
    }

    ~DeepCopy() {
        delete[] _data;
    }

    void print() const {
        std::cout << _data << std::endl;
    }

private:
    char* _data;
};

int main() {
    DeepCopy obj1("Hello");
    DeepCopy obj2 = obj1; // 深拷贝

    obj1.print(); // 输出: Hello
    obj2.print(); // 输出: Hello

    return 0;
}

区别总结

  • 浅拷贝:复制对象的引用,两个对象共享同一块内存,修改一个对象会影响另一个对象。
  • 深拷贝:复制对象的内容,两个对象独立存在,修改一个对象不会影响另一个对象。

2 代码实现

1. 引入必要的头文件

#include <cstring> // 用于strlen, strcpy, strcmp, memmove, memcpy, memset等函数
#include <cassert> // 用于assert断言检查
#include <algorithm> // 用于std::swap交换函数

2. 类定义及类型别名

class string {
public:
    typedef char* iterator; // 定义迭代器类型,方便遍历字符串

3. 构造函数

    // 默认构造函数,初始化为空字符串或给定的C风格字符串
    string(const char* str = "") {
        _size = strlen(str);
        _capacity = _size;
        _str = new char[_capacity + 1];
        strcpy(_str, str);
    }

4. 复制构造函数与赋值操作符

    // 复制构造函数,使用copy-and-swap技巧
    string(const string& s) : _str(nullptr), _size(0), _capacity(0) {
        string tmp(s._str); // 创建一个临时对象
        this->swap(tmp); // 与临时对象交换数据
    }

    // 复制赋值操作符,同样使用copy-and-swap技巧
    string& operator=(string s) {
        this->swap(s); // 与传入的对象交换数据
        return *this;
    }

5. 析构函数

    // 析构函数,释放分配的内存
    ~string() {
        if (_str) {
            delete[] _str;
            _str = nullptr;
        }
    }

6. 迭代器支持

    // 迭代器支持,用于遍历字符串
    iterator begin() { return _str; }
    iterator end() { return _str + _size; }

7. 修改操作

    // 在字符串末尾添加一个字符
    void push_back(char c) {
        if (_size == _capacity)
            reserve(_capacity * 2); // 如果容量不足,增加容量

        _str[_size++] = c;
        _str[_size] = '\0'; // 空终止符
    }

    // 重载+=操作符,用于添加单个字符
    string& operator+=(char c) {
        push_back(c);
        return *this;
    }

8. 字符串附加操作

    // 附加一个C风格字符串
    void append(const char* str) {
        size_t len = strlen(str);
        if (_size + len > _capacity)
            reserve(_size + len); // 确保有足够的容量

        strcat(_str, str); // 追加字符串
        _size += len;
    }

    // 重载+=操作符,用于附加C风格字符串
    string& operator+=(const char* str) {
        append(str);
        return *this;
    }

9. 清空字符串

    // 清空字符串
    void clear() {
        _size = 0;
        _str[_size] = '\0'; // 空终止符
    }

10. 交换操作

    // 交换两个字符串的数据
    void swap(string& s) {
        std::swap(_str, s._str);
        std::swap(_size, s._size);
        std::swap(_capacity, s._capacity);
    }

11. 获取C风格字符串

    // 获取C风格字符串
    const char* c_str() const {
        return _str;
    }

12. 容量相关操作

    // 获取字符串的大小、容量和是否为空
    size_t size() const { return _size; }
    size_t capacity() const { return _capacity; }
    bool empty() const { return _size == 0; }

    // 调整字符串的大小
    void resize(size_t newSize, char c = '\0') {
        if (newSize > _size) {
            if (newSize > _capacity)
                reserve(newSize); // 确保有足够的容量

            memset(_str + _size, c, newSize - _size);
        }

        _size = newSize;
        _str[newSize] = '\0'; // 空终止符
    }

    // 预留内存空间
    void reserve(size_t newCapacity) {
        if (newCapacity > _capacity) {
            char* str = new char[newCapacity + 1];
            strcpy(str, _str); // 复制现有字符串

            delete[] _str; // 释放旧的内存
            _str = str;
            _capacity = newCapacity;
        }
    }

13. 访问操作符

    // 方括号访问操作符
    char& operator[](size_t index) {
        assert(index < _size);
        return _str[index];
    }

    const char& operator[](size_t index) const {
        assert(index < _size);
        return _str[index];
    }

14. 字符串比较操作符

    // 字符串比较操作符
    bool operator<(const string& s) {
        return strcmp(_str, s._str) < 0;
    }

    bool operator<=(const string& s) {
        return strcmp(_str, s._str) <= 0;
    }

    bool operator>(const string& s) {
        return strcmp(_str, s._str) > 0;
    }

    bool operator>=(const string& s) {
        return strcmp(_str, s._str) >= 0;
    }

    bool operator==(const string& s) {
        return strcmp(_str, s._str) == 0;
    }

    bool operator!=(const string& s) {
        return strcmp(_str, s._str) != 0;
    }

15. 字符串查找操作

    // 查找单个字符或子字符串
    size_t find(char c, size_t pos = 0) const {
        for (size_t i = pos; i < _size; ++i) {
            if (_str[i] == c) {
                return i;
            }
        }
        return string::npos; // 未找到
    }

    size_t find(const char* s, size_t pos = 0) const {
        size_t len = strlen(s);
        for (size_t i = pos; i <= _size - len; ++i) {
            if (strncmp(_str + i, s, len) == 0) {
                return i;
            }
        }
        return string::npos; // 未找到
    }

16. 插入操作

    // 在指定位置插入单个字符或子字符串
    string& insert(size_t pos, char c) {
        if (pos > _size) {
            throw std::out_of_range("Position out of range");
        }

        if (_size + 1 > _capacity) {
            reserve(_size + 1); // 确保有足够的容量
        }

        memmove(_str + pos + 1, _str + pos, _size - pos + 1);
        _str[pos] = c;
        ++_size;
        return *this;
    }

    string& insert(size_t pos, const char* str) {
        size_t len = strlen(str);
        if (pos > _size) {
            throw std::out_of_range("Position out of range");
        }

        if (_size + len > _capacity) {
            reserve(_size + len); // 确保有足够的容量
        }

        memmove(_str + pos + len, _str + pos, _size - pos + 1);
        memcpy(_str + pos, str, len);
        _size += len;
        return *this;
    }

17. 删除操作

    // 删除指定位置的字符或子字符串
    string& erase(size_t pos, size_t len) {
        if (pos > _size || pos + len > _size) {
            throw std::out_of_range("Position out of range");
        }

        memmove(_str + pos, _str + pos + len, _size - pos - len + 1);
        _size -= len;
        return *this;
    }

18. 友元函数:输入输出流操作

private:
    friend ostream& operator<<(ostream& _cout, const string& s); // 输出流操作符
    friend istream& operator>>(istream& _cin, string& s); // 输入流操作符

    char* _str;
    size_t _capacity;
    size_t _size;
};

19. 输出流操作符

// 输出流操作符,用于输出字符串
ostream& operator<<(ostream& _cout, const string& s) {
    for (size_t i = 0; i < s.size(); ++i) {
        _cout << s[i];
    }
    return _cout;
}

以上是按功能块拆分的代码,每一块都有对应的中文注释解释其功能和作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值