一般面試,已知類String的原型為:
class String { public: String(const char *str = NULL);// 普通構造函數 String(const String &str);// 拷貝構造函數 ~String(void);// 析構函數 String & operator = (const String &str);// 賦值函數 private: char *m_data;// 用於保存字符串 };
類的實現:
String::String(const char *str) { if (str == NULL) { m_data = new char[1];// 得分點:對空字符串自動申請存放結束標志'\0'的,加分點:對m_data加NULL判斷 *m_data = '\0'; } else { int length = strlen(str); m_data = new char[length + 1];// 若能加 NULL 判斷則更好 strcpy(m_data, str); } } // String的析構函數 String::~String(void) { delete[] m_data; // 或delete m_data; } //拷貝構造函數 String::String(const String &str)// 得分點:輸入參數為const型 { int length = strlen(str.m_data); m_data = new char[length + 1];// 若能加 NULL 判斷則更好 strcpy(m_data, str.m_data); } //賦值函數 String & String::operator = (const String &str) // 得分點:輸入參數為const型 { if (this == &str)//得分點:檢查自賦值 return *this; if (m_data) delete[] m_data;//得分點:釋放原有的內存資源 int length = strlen(str.m_data); m_data = new char[length + 1];//加分點:對m_data加NULL判斷 strcpy(m_data, str.m_data); return *this;//得分點:返回本對象的引用 }
完整版:
一 整體框架
除了以上四個必須的函數,這里還實現了一些附加的內容。
- 若干個運算符重載,這里的幾個是常見的運算符,可以加深對String的認識和運算符重載的理解。
- 兩個常用的函數,包括取字符串長度和取C類型的字符串。
- 兩個處理輸入輸出的運算符重載,為了使用的方便,這里把這兩個運算符定義為友元函數。
整體的類的框架如下所示。
class String { public: String(const char *str = NULL); //通用構造函數 String(const String &str); //拷貝構造函數 ~String(); //析構函數 String operator+(const String &str) const; //重載+ String& operator=(const String &str); //重載= String& operator+=(const String &str); //重載+= bool operator==(const String &str) const; //重載== char& operator[](int n) const; //重載[] size_t size() const; //獲取長度 const char* c_str() const; //獲取C字符串 friend istream& operator>>(istream &is, String &str);//輸入 friend ostream& operator<<(ostream &os, String &str);//輸出 private: char *data; //字符串 size_t length; //長度 }; //注意,類的成員函數中,有一些是加了const修飾的,表示這個函數不會對類的成員進行任何修改。一些函數的輸入參數也加了const修飾,表示該函數不會對改變這個參數的值。
二 具體實現
/*下面逐個進行成員函數的實現。 同樣構造函數適用一個字符串數組進行String的初始化,默認的字符串數組為空。這里的函數定義中不需要再定義參數的默認值,因為在類中已經聲明過了。 另外,適用C函數strlen的時候需要注意字符串參數是否為空,對空指針調用strlen會引發內存錯誤。*/ String::String(const char *str)//通用構造函數 { if (!str) { length = 0; data = new char[1]; *data = '\0'; } else { length = strlen(str); data = new char[length + 1]; strcpy(data, str); } } //拷貝構造函數需要進行深復制。 String::String(const String &str)//拷貝構造函數 { length = str.size(); data = new char[length + 1]; strcpy(data, str.c_str()); } //析構函數需要進行內存的釋放及長度的歸零。 String::~String()//析構函數 { delete []data; length = 0; } //重載字符串連接運算,這個運算會返回一個新的字符串。 String String::operator+(const String &str) const//重載+ { String newString; newString.length = length + str.size(); newString.data = new char[newString.length + 1]; strcpy(newString.data, data); strcat(newString.data, str.data); return newString; } //重載字符串賦值運算,這個運算會改變原有字符串的值,為了避免內存泄露,這里釋放了原先申請的內存再重新申請一塊適當大小的內存存放新的字符串。 String& String::operator=(const String &str)//重載= { if (this == &str) return *this; delete []data; length = str.length; data = new char[length + 1]; strcpy(data, str.c_str()); return *this; } //重載字符串+=操作,總體上是以上兩個操作的結合。 String& String::operator+=(const String &str)//重載+= { length += str.length; char *newData = new char[length + 1]; strcpy(newData, data); strcat(newData, str.data); delete []data; data = newData; return *this; } //重載相等關系運算,這里定義為內聯函數加快運行速度。 inline bool String::operator==(const String &str) const//重載== { if (length != str.length) return false; return strcmp(data, str.data) ? false : true; } //重載字符串索引運算符,進行了一個簡單的錯誤處理,當長度太大時自動讀取最后一個字符。 inline char& String::operator[](int n) const//重載[] { if (n >= length) return data[length-1]; //錯誤處理 else return data[n]; } //重載兩個讀取私有成員的函數,分別讀取長度和C字符串。 inline size_t String::size() const//獲取長度 { return length; } //重載輸入運算符,先申請一塊足夠大的內存用來存放輸入字符串,再進行新字符串的生成。這是一個比較簡單朴素的實現,網上很多直接is>>str.data的方法是錯誤的,因為不能確定str.data的大小和即將輸入的字符串的大小關系。 istream& operator>>(istream &is, String &str)//輸入 { char tem[1000]; //簡單的申請一塊內存 is >> tem; str.length = strlen(tem); str.data = new char[str.length + 1]; strcpy(str.data, tem); return is; } //重載輸出運算符,只需簡單地輸出字符串的內容即可。注意為了實現形如cout<<a<<b的連續輸出,這里需要返回輸出流。上面的輸入也是類似。 ostream& operator<<(ostream &os, String &str)//輸出 { os << str.data; return os; } inline const char* String::c_str() const//獲取C字符串 { return data; }
三 功能測試
編碼完成后需要對代碼進行測試,以下是一個簡單但不夠嚴謹的測試。
int main() { String s; cin >> s; cout << s << ": " << s.size() << endl; char a[] = "Hello", b[] = "World!"; String s1(a), s2(b); cout << s1 << " + " << s2 << " = " << s1 + s2 << endl; String s3 = s1 + s2; if (s1 == s3) cout << "First: s1 == s3" << endl; s1 += s2; if (s1 == s3) cout << "Second: s1 == s3" << endl; /*程序輸入輸出為: 123456789 123456789: 9 Hello + World! = HelloWorld! Second: s1 == s3 Press any key to continue . . . */ }
原文: