實現一個string類(C++)
阿新 • • 發佈:2021-06-29
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_INCLUDED2 #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 }