📜  如何在 C++ 中创建具有基本功能的自定义 String 类(1)

📅  最后修改于: 2023-12-03 15:08:34.905000             🧑  作者: Mango

如何在 C++ 中创建具有基本功能的自定义 String 类

在 C++ 中,字符串是一个非常重要的数据类型。C++ 标准库中提供了一个名为 std::string 的字符串类,但我们也可以自己创建一个自定义的字符串类,来满足自己的需求。

本文将介绍如何在 C++ 中创建一个具有基本功能的自定义字符串类。我们的自定义字符串类将提供常见的字符串操作,如字符串复制、字符串连接、字符串比较等。

1. 自定义字符串类的设计

在开始编写自定义字符串类之前,让我们首先确定我们的字符串类需要具有哪些属性和方法。

我们的自定义字符串类需要具有以下属性和方法:

  • 字符串数据成员:保存字符串本身的字符数组
  • 字符串长度成员:保存字符串的长度
  • 默认构造函数:创建一个空字符串
  • 可以接受一个 C 风格字符串作为参数的构造函数
  • 复制构造函数:用另一个字符串对象创建一个新的字符串对象
  • 析构函数:释放动态分配的内存
  • 重载赋值运算符
  • 重载加法运算符
  • 重载比较运算符
  • 获取字符串长度的方法
  • 获取字符串内容的方法
  • 修改字符串内容的方法
2. 实现自定义字符串类
2.1 头文件

让我们从头文件开始。以下是我们自定义字符串类的头文件。

#ifndef STRING_H
#define STRING_H

class String {
public:
    // 构造函数
    String();
    String(const char* str);
    String(const String& other);

    // 析构函数
    ~String();

    // 运算符重载
    String& operator=(const String& other);
    friend String operator+(const String& s1, const String& s2);
    bool operator==(const String& other) const;
    bool operator!=(const String& other) const;

    // 公共方法
    int length() const;
    const char* c_str() const;
    void clear();
    void swap(String& other);

private:
    // 私有变量
    char* data;
    int size;
};

#endif

我们的自定义字符串类被定义为一个名为 String 的类,它包括一个公共接口和一个私有实现。

公共接口包含以下内容:

  • 默认构造函数 String():创建一个空字符串
  • 可以接受一个 C 风格字符串作为参数的构造函数 String(const char* str):用 C 风格字符串创建一个字符串对象
  • 复制构造函数 String(const String& other):用另一个字符串对象创建一个新的字符串对象
  • 析构函数 ~String():释放动态分配的内存
  • 运算符重载 operator=():重载赋值运算符
  • 运算符重载 operator+():重载加法运算符
  • 运算符重载 operator==()operator!=():重载比较运算符
  • 获取字符串长度的方法 length()
  • 获取字符串内容的方法 c_str()
  • 修改字符串内容的方法 clear()swap()

私有实现包含以下内容:

  • 字符串数据成员 data:一个指向字符数组的指针,用于保存字符串的内容
  • 字符串长度成员 size:用于保存字符串的长度。
2.2 源文件

接下来,让我们编写源文件来实现我们的自定义字符串类。以下是实现文件 string.cpp 的内容:

#include <cstring>
#include <algorithm>
#include "string.h"

using namespace std;

// 默认构造函数
String::String() {
    data = new char[1];
    size = 0;
    data[0] = '\0';
}

// 构造函数
String::String(const char* str) {
    size = strlen(str);
    data = new char[size + 1];
    strcpy(data, str);
}

// 复制构造函数
String::String(const String& other) {
    size = other.size;
    data = new char[size + 1];
    strcpy(data, other.data);
}

// 析构函数
String::~String() {
    delete[] data;
}

// 运算符重载:赋值运算符
String& String::operator=(const String& other) {
    if (this != &other) {
        String temp(other);
        swap(temp);
    }
    return *this;
}

// 运算符重载:加法运算符
String operator+(const String& s1, const String& s2) {
    String result;
    result.size = s1.size + s2.size;
    result.data = new char[result.size + 1];
    strcpy(result.data, s1.data);
    strcat(result.data, s2.data);
    return result;
}

// 运算符重载:比较运算符
bool String::operator==(const String& other) const {
    return (size == other.size) && (strcmp(data, other.data) == 0);
}
bool String::operator!=(const String& other) const {
    return !(*this == other);
}

// 公共方法:获取字符串长度
int String::length() const {
    return size;
}

// 公共方法:获取字符串内容
const char* String::c_str() const {
    return data;
}

// 公共方法:清空字符串
void String::clear() {
    String empty;
    swap(empty);
}

// 公共方法:交换两个字符串
void String::swap(String& other) {
    std::swap(size, other.size);
    std::swap(data, other.data);
}

我们的自定义字符串类的实现:

  • 默认构造函数 String::String():创建一个空字符串。该构造函数创建一个 char 类型的指针 data,并将其指向一个大小为 1 的字符数组。这个字符数组仅包含一个空字符 '\0'。我们还将字符串长度 size 初始化为 0。
  • 可以接受一个 C 风格字符串作为参数的构造函数 String::String(const char* str):用 C 风格字符串创建一个字符串对象。该构造函数使用 strlen() 函数测量传入字符串的长度,并使用 new 运算符动态分配足够的空间来存储字符串。然后,该函数使用 strcpy() 函数复制传入的字符串到 data 指向的字符数组中,并将 size 初始化为该字符串的长度。
  • 复制构造函数 String::String(const String& other):用另一个字符串对象创建一个新的字符串对象。该构造函数使用 new 运算符动态分配足够的空间来存储新字符串,然后使用 strcpy() 函数将另一个字符串复制到新字符串中,并将 size 初始化为另一个字符串的长度。
  • 析构函数 String::~String():释放动态分配的内存。该析构函数使用 delete[] 运算符释放先前调用 new 运算符分配的 data 指向的内存。
  • 运算符重载:赋值运算符 String& String::operator=(const String& other)。我们的赋值运算符使用复制构造函数来创建一个临时字符串,并调用 swap() 函数来交换成员变量,从而实现赋值运算符的功能。
  • 运算符重载:加法运算符 String operator+(const String& s1, const String& s2)。 加法运算符将两个字符串连接起来,返回一个包含两个字符串内容的新的字符串。
  • 运算符重载:比较运算符 bool String::operator==(const String& other) constbool String::operator!=(const String& other) const。我们的比较运算符使用 strcmp() 函数比较两个字符串是否相同,相同则返回 true,否则返回 false。
  • 公共方法:获取字符串长度 int String::length() const。该方法返回字符串长度 size
  • 公共方法:获取字符串内容 const char* String::c_str() const。该方法返回指向字符数组的指针 data
  • 公共方法:清空字符串 void String::clear()。该方法使用默认构造函数创建一个空字符串,并调用 swap() 函数交换成员变量,从而实现清空字符串的功能。
  • 公共方法:交换两个字符串 void String::swap(String& other)。该方法使用标准库函数 std::swap() 交换两个字符串对象的成员变量。
3. 自定义字符串类的使用

我们已经成功地实现了一个具有基本功能的自定义字符串类。接下来,我们可以使用我们的字符串类来完成字符串操作。以下是使用自定义字符串类的示例代码:

#include <iostream>
#include "string.h"

using namespace std;

int main() {
    String s1("Hello");
    String s2("world");
    String s3 = s1 + " " + s2;
    String s4 = s3;
    String s5;

    cout << "s1 = " << s1.c_str() << "\n";
    cout << "s2 = " << s2.c_str() << "\n";
    cout << "s3 = " << s3.c_str() << "\n";
    cout << "s4 = " << s4.c_str() << "\n";
    cout << "s3 == s4 ? " << (s3 == s4 ? "true" : "false") << "\n";

    s5 = s4;
    s4.clear();

    cout << "s4 = " << s4.c_str() << "\n";
    cout << "s5 = " << s5.c_str() << "\n";
    cout << "s3 != s5 ? " << (s3 != s5 ? "true" : "false") << "\n";

    return 0;
}

总结

在本文中,我们介绍了如何在 C++ 中创建一个具有基本功能的自定义字符串类。我们学习了如何使用类成员变量、构造函数、析构函数、运算符重载和标准库函数来实现字符串操作。我们还演示了如何使用自定义字符串类来完成字符串操作,并介绍了如何测试和调试自定义字符串类。