实现一个string类(C++)

Posted on 2021-06-29 20:52  foghorn  阅读(1737)  评论(0编辑  收藏  举报

0 说明

  本文仅实现string类中几种重要、常用的功能,旨在掌握C++类设计的关键知识点。

1 知识点

  • 构造函数(包括默认构造函数、拷贝构造函数以及自定义的其他构造函数)
  • 运算符重载
  • 友元
  • 析构函数
  • C风格字符的操作

2 类的设计

  为使代码简洁,本文采取分文件编写模式,类的声明包含在头文件"mystring.h"中,成员的实现包含在源文件"mystring.h"中,"main.cpp"文件是若干测试。

2.1 构造函数

  类比C++中原有的string类,我们可以定义一个string对象(不指定初始值),可以用一个已存在的string对象初始化一个新定义的对象,也可以用一个C风格字符串给一个string对象赋值。为了实现同样的功能,自定义的String类需要如下几种构造函数:

  • 默认构造函数:String(),用于直接构建一个不指定初值的对象
  • 拷贝构造函数:String(const String& s),用于初始化新的对象
  • 普通有参构造函数:String(const String* s),用于以C风格字符串初始化一个对象

2.2 重载函数

  由于String类是我们自定义的,所以有必要重载若干常用运算符以丰富String类所支持的功能。具体地,本文将重载一下运算符:

  • = 运算符,=运算符给已存在的对象赋值,我们将重载以String对象赋值和以C风格字符串赋值两种形式
  • == 运算符,用于判断两个String对象是否相同
  • > 运算符,判断一个对象是否大于另一个对象
  • < 运算符,判断一个对象是否小于另一个对象
  • += 运算符,将两个对象拼接到一起
  • [] 运算符,访问字符串某个位置的元素,分为常量和非常量两个版本重载
  • << 运算符,输出一个String对象
  • >> 运算符,实现读入一个字符流到String对象

2.3 普通成员函数

  只设计一个length()函数用于获取字符串的长度。

2.4 析构函数

  析构函数无法重载较为简单,一个类中只能有一个析构函数,后续介绍析构函数的内部实现,这里不做过多阐述。

2.5 成员变量

  只设计一个变量len用于记录字符串的长度。

  类的设计部分代码如下:

 1 #ifndef MYSTRING_H_INCLUDED
 2 #define MYSTRING_H_INCLUDED
 3 
 4 #include <iostream>
 5 
 6 using namespace std;
 7 
 8 class String {
 9 public:
10     // constructor function
11     String();  // default constructor function
12     String(const String& s);  // copy constructor function
13     String(const char* s);
14 
15     // overload function
16     String& operator=(const String& s);  //
17     String& operator=(const char* s);
18     String& operator+=(const String& s);
19     friend int operator==(const String& s1, const String& s2);
20     friend int operator>(const String& s1, const String& s2);
21     friend int operator<(const String& s1, const String& s2);
22     char& operator[](int i);
23     const char& operator[](int i) const;
24     friend ostream& operator<<(ostream& os, String& s);
25     friend istream& operator>>(istream& is, String& s);
26 
27     // common function
28     int length() const;
29 
30     //
31     ~String();
32 
33 private:
34     char* str;
35     int len;
36 };
37 
38 
39 
40 #endif // MYSTRING_H_INCLUDED

3 成员设计

3.1 构造函数

  • 默认构造函数:String()

  将默认值设置为空,因此只需申请一个char大小的内存空间用于存放C风格字符串结尾标志 ‘\0’。

1 String::String() {
2     len = 0;
3     str = new char[1];
4     str[0] = '\0';
5 }
  • 拷贝构造函数:String(const String& s)

  首先判断s是否为空,然后更新新字符串的长度,接着开辟一段内存空间,最后用strcpy()函数将s.str复制到新的字符串中。

1 String::String(const String& s) {
2     if (s.length() == 0) {
3         String();
4     }
5     len = s.len;
6     str = new char[len + 1];
7     strcpy(str, s.str);
8 }
  • 普通有参构造函数:String(const String* s)

  与拷贝构造函数类似。

1 String::String(const char* s) {
2     if (s == nullptr) {
3         String();
4     }
5     len = strlen(s);
6     str = new char[len + 1];
7     strcpy(str, s);
8 

3.2 运算符重载

  • 赋值运算符(类对象版):=

  先判断等号两侧对象是否相同。释放原对象内存是关键。

 1 String& String::operator=(const String& s) {
 2     if (this == &s) {
 3         return *this;
 4     }
 5 
 6     delete []str;
 7     int len = s.length();
 8     str = new char[len + 1];
 9     strcpy(str, s.str);
10 
11     return *this;
12 }
  • 赋值运算符(C风格字符串版):=
1 String& String::operator=(const char* s) {
2     delete []str;
3     len = strlen(s);
4     str = new char[len + 1];
5     strcpy(str, s);
6 
7     return *this;
8 }
  • 重载运算符:+=

  采用成员函数的方式重载,只需传递一个参数。将运算符左侧对象复制一份到新对象c中,然后删除运算符左侧对象原有的的内存空间,再扩容、字符拷贝、释放临时对象c。

 1 String& String::operator+=(const String& s) {
 2     String c(*this);
 3     delete []this->str;
 4     this->str = new char[this->length() + s.length()];
 5     stpcpy(this->str, c.str);
 6     stpcpy(this->str, s.str);
 7     this->len += s.length();
 8     delete []c.str;
 9     
10     return *this;
11 }
  • 重载比较运算符:==、<,>
 1 int operator==(const String& s1, const String& s2) {
 2     return (strcmp(s1.str, s2.str) == 0);
 3 }
 4 
 5 int operator>(const String& s1, const String& s2) {
 6     return (strcmp(s1.str, s2.str) > 0);
 7 }
 8 
 9 int operator<(const String& s1, const String& s2) {
10     return (strcmp(s1.str, s2.str) < 0);
11 }
  • 重载运算符:[]
1 char& String::operator[](int i) {
2     return str[i];
3 }
4 const char& String::operator[](int i) const {
5     return str[i];
6 }
  • 重载输入输出运算符:>>、<<
 1 ostream & operator<<(ostream& os, String& s) {
 2     os << s.str;
 3     return os;
 4 }
 5 
 6 istream& operator>>(istream& is, String& s){
 7     char temp[80];
 8     cin.getline(temp, 80);
 9     //is >> temp;
10     s = temp;
11 
12     return is;
13 }

3.3 普通成员函数

  • 获取字符串长度:length()
1 int String::length() {
2     return len;
3 }

3.4 析构函数

1 String::~String() {
2     delete []str;
3 }

4 测试

 1 int main()
 2 {
 3     String str1("abc");
 4     String str2(str1);
 5     String str3;
 6     str3 = str2;
 7     cout << "str1的长度: " << str1.length() << endl;
 8     cout << "str1[0] = " << str1[0] << endl;
 9     cout << "str1 = " << str1 << endl;
10     cout << "str3 = " << str3 << endl;
11     cin >> str3;
12     cout << "str3 = " << str3 << endl;
13     cout << "str3的长度: " << str3.length() << endl;
14     return 0;
15 }

 

Copyright © 2024 foghorn
Powered by .NET 9.0 on Kubernetes