好的!下面是一个完整教程:如何手搓一个 STL 风格的 string 容器类(自定义 String 类),它模仿 std::string 的常用接口,具备基本的字符串管理功能,包括构造、拷贝、移动、运算符重载等,结构清晰、逻辑易懂,适合作为 C++ 面向对象 + 运算符重载 + RAII 内存管理 的综合练习。


✅ 一、项目目标

实现一个类 MyString,支持以下功能:

功能示例
构造与析构MyString s("hello");
拷贝与移动MyString s2 = s1;
字符访问s[0]
长度查询s.size()
拼接运算s1 + s2
比较运算==, !=, <
输出重载std::cout << s;

🧱 二、核心类声明

#ifndef MYSTRING_H
#define MYSTRING_H

#include <iostream>
#include <cstring>

class MyString {
private:
    char* data;
    size_t len;

public:
    // 构造 & 析构
    MyString();                      // 默认构造
    MyString(const char* str);       // C风格字符串构造
    MyString(const MyString& other); // 拷贝构造
    MyString(MyString&& other) noexcept; // 移动构造
    ~MyString();                     // 析构

    // 运算符重载
    MyString& operator=(const MyString& other); // 拷贝赋值
    MyString& operator=(MyString&& other) noexcept; // 移动赋值

    char& operator[](size_t index);
    const char& operator[](size_t index) const;

    MyString operator+(const MyString& other) const;

    bool operator==(const MyString& other) const;
    bool operator<(const MyString& other) const;

    size_t size() const;

    // 流输出
    friend std::ostream& operator<<(std::ostream& os, const MyString& s);
};

#endif

⚙️ 三、核心实现(MyString.cpp

#include "MyString.h"

// 默认构造
MyString::MyString() : data(new char[1]{'\0'}), len(0) {}

// C风格字符串构造
MyString::MyString(const char* str) {
    len = strlen(str);
    data = new char[len + 1];
    strcpy(data, str);
}

// 拷贝构造
MyString::MyString(const MyString& other) {
    len = other.len;
    data = new char[len + 1];
    strcpy(data, other.data);
}

// 移动构造
MyString::MyString(MyString&& other) noexcept : data(other.data), len(other.len) {
    other.data = nullptr;
    other.len = 0;
}

// 析构
MyString::~MyString() {
    delete[] data;
}

// 拷贝赋值
MyString& MyString::operator=(const MyString& other) {
    if (this != &other) {
        delete[] data;
        len = other.len;
        data = new char[len + 1];
        strcpy(data, other.data);
    }
    return *this;
}

// 移动赋值
MyString& MyString::operator=(MyString&& other) noexcept {
    if (this != &other) {
        delete[] data;
        data = other.data;
        len = other.len;
        other.data = nullptr;
        other.len = 0;
    }
    return *this;
}

// 索引访问
char& MyString::operator[](size_t index) {
    return data[index];
}

const char& MyString::operator[](size_t index) const {
    return data[index];
}

// 拼接
MyString MyString::operator+(const MyString& other) const {
    char* new_data = new char[len + other.len + 1];
    strcpy(new_data, data);
    strcat(new_data, other.data);
    MyString result(new_data);
    delete[] new_data;
    return result;
}

// 比较
bool MyString::operator==(const MyString& other) const {
    return strcmp(data, other.data) == 0;
}

bool MyString::operator<(const MyString& other) const {
    return strcmp(data, other.data) < 0;
}

// 长度
size_t MyString::size() const {
    return len;
}

// 输出流重载
std::ostream& operator<<(std::ostream& os, const MyString& s) {
    os << s.data;
    return os;
}

🎯 四、使用示例(main.cpp)

#include "MyString.h"

int main() {
    MyString a("Hello");
    MyString b("World");
    MyString c = a + MyString(" ") + b;

    std::cout << "c: " << c << std::endl;
    std::cout << "Length: " << c.size() << std::endl;

    if (a < b) {
        std::cout << a << " is less than " << b << std::endl;
    }

    MyString d = c;
    std::cout << "Copy d: " << d << std::endl;

    MyString e = std::move(d);
    std::cout << "Move e: " << e << std::endl;
}

🧠 五、你学到的知识点

知识点说明
RAII 原则动态内存管理用构造/析构控制
拷贝控制五法则构造、析构、拷贝构造、赋值、移动
运算符重载+、==、[]、<<
资源管理深拷贝 vs. 移动语义
面向对象封装接口友好,隐藏实现细节

📦 六、扩展方向(可选挑战)

  • ✅ 支持 UTF-8 / 多字节字符处理
  • ✅ 实现 inserterasefindsubstr 等接口
  • ✅ 实现迭代器接口(支持 begin()/end()
  • ✅ 兼容 C++ STL allocator 策略
  • ✅ 编写单元测试 & 性能测试

如果你希望我把这个项目打包成完整的工程目录结构(含 Makefile / CMake / 注释文档),或想在此基础上进一步封装为库,请告诉我,我可以继续帮你完善它。是否要我做成一个 GitHub 项目模板?