1. 程式人生 > 其它 >實現一個string類(C++)

實現一個string類(C++)

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 }