自定義實現字元串string的介面

来源:http://www.cnblogs.com/hchacha/archive/2017/07/29/7253312.html
-Advertisement-
Play Games

用char*管理String類的記憶體,new動態分配,在析構函數中delete char*指向的new出來的記憶體,一個string類需要實現那些介面可參考標準庫里的string: http://www.cplusplus.com/reference/string/string/ 實現思路是:在創建S ...


用char*管理String類的記憶體,new動態分配,在析構函數中delete char*指向的new出來的記憶體,一個string類需要實現那些介面可參考標準庫里的string:  http://www.cplusplus.com/reference/string/string/ 

  • 實現思路是:在創建String、String需要伸縮(如賦值時需要調整大小、字元串相加也需要更大的空間)時重新new記憶體,並釋放掉原有記憶體;標準庫string的空間是預先分配的,有多餘的空間可用,如果string需要伸縮,就開闢新的記憶體空間。
  • >>重載的思路是:用cin.getline來讀取標準輸入到字元指針指向的空間——空間有個預設的大小,如100,可以接收包含有空格的字元串
  • String初始化為空字元串("\0"或 ""是等價的),也需要new字元數組,這樣才能delete,如果用char *data="\0",不能用delete釋放不是new出來的記憶體
  • []需要重載兩個版本,const版本 const char& operator[](size_t index) const; const成員函數的this指針隱式的轉換為指向常量的指針: operator(const  String *this, size_t index),const對象只能調用const menber function
  • 不需要重載解引用*和取地址&,它們對自定義的類型也支持
  • +=調用了operator+,問為什麼operator+要返回引用,而不能返回對象?
  • 沒有實現重載的relational operators
  • 相比標準庫,自定義的String實現的介面很少,似乎什麼都做不了,只能創建,賦值,輸出,訪問元素,甚至連標準庫里的string開發中也不好用:為什麼大多數的C++的開源庫都喜歡自己實現一個string? 
  • new管理記憶體是否存在memory leak,是否有隱含的錯誤?
  1 #include<iostream>
  2 #include<string>
  3 #include<vector>
  4 #include<algorithm>
  5 #include<cstdio>
  6 #include<complex>
  7 #include<new>
  8 #include<memory>
  9 #include<exception>
 10 using namespace std;
 11 // interfaces should supported 
 12 //用char*管理記憶體
 13 class String
 14 {
 15 public:
 16     String();
 17     String(const char*s);
 18     String(size_t n, const char c);//用字元c填充String
 19     String(const String&s);
 20     String& operator=(const String&rhs);
 21     String& operator=(const char*c);
 22     char& operator[](size_t index);//要提供[]的兩個版本
 23     const char& operator[](size_t index)const;
 24     String & operator*();//解引用重載是多餘的,語言本身支持對所有類型的指針解引用,包括了自定義類型
 25     String& operator+(const String&rhs);
 26     String& operator+=(const String&rhs);
 27     bool operator==(const String&rhs);
 28     friend bool operator<(const String&lhs, const String&rhs);
 29     friend ostream& operator<<(ostream& os, const String&rhs);
 30     friend istream& operator>>(istream& in, String&rhs);
 31     size_t size(); //如果是size_t length()會導致。。。。。
 32     bool empty();
 33     const char* c_str();
 34     ~String();
 35 private:
 36     char * data;
 37     size_t length;
 38 
 39 };
 40 String::String() //類外面定義menber function ,域作用符
 41 {
 42     this->data = new char[1](); //空字元串 ,strlen對data運算得到的長度為0
 43     data[0] = '\0';
 44     (*this).length = 0;
 45 }
 46 String::String(const char*s) //允許implicit類型轉換
 47 {
 48     // 不能用data=s;這導致創建的String對象與s共用了字元,而不是副本
 49     length = strlen(s);
 50     data = new char[length + 1]();//value initialization,申請了字元指針指向的記憶體區域
 51     strcpy(data, s);
 52     *(data + length) = '\0';
 53 }
 54 String::String(size_t n, const char c)
 55 {
 56     length = n;
 57     data = new char[length + 1]();
 58     for (size_t i = 0; i < length;i++)
 59     {
 60         *(data + i) = c;
 61     }
 62     *(data + length) = '\0';
 63 }
 64 String::String(const String&s)
 65 {
 66     length = s.length;
 67     data = new char[length + 1](); //untill deconstructor to destory newed memory
 68     for (size_t i = 0; i < length;i++)
 69     {
 70         data[i] = s.data[i];
 71     }
 72     data[length] = '\0';
 73 }
 74 String& String::operator=(const String&rhs)
 75 {
 76     if (this->data == rhs.data) return *this;// 支持*this==rhs的關係比較操作嗎?
 77     
 78     //assign 不是初始化,不需要申請記憶體空間,拷貝構造需要 ,但是原String與rhs大小可能不一樣
 79     delete[]data; //會導致重覆刪除data所指記憶體嗎??
 80     
 81     length = rhs.length;
 82     data = new char[length + 1]();
 83     //如果發生異常
 84 
 85     if (data == NULL)  throw "allocate memory failed in copy ctr";
 86     for (size_t i = 0; i < length; i++)
 87     {
 88         data[i] = rhs.data[i];
 89     }
 90     data[length] = '\0';
 91 }
 92 char& String::operator[](size_t index)
 93 {
 94     if (index >= length||index<0) throw "out of range";
 95     return data[index];//如果data指向的字元串為"dhaj"這種不可修改的,會導致返回的引用不能有s[i]='c'的修改操作
 96 }
 97 String& String:: operator*()
 98 {
 99     if (this == NULL) throw "dereferrence null pointer ";
100     return *this;
101 }
102 String& String::operator+(const String&rhs)//a+b形式,也不改變a
103 {
104     String s;//不可伸縮,不能用來存a+b的結果
105     int len = strlen(this->data) + strlen(rhs.data);
106     char *p = new char[len + 1]();
107     for (size_t i = 0; i < strlen(this->data); i++)
108     {
109         p[i] = this->data[i];
110     }
111     for (int j = strlen(this->data),i=0; j < len; j++,i++)
112     {
113         p[j] = rhs.data[i];
114     }
115     p[len] = '\0';
116     String *t = new String(p); //new了一個p,一個t,可以釋放掉p,因為t是p的副本
117     delete[]p;
118     return *t;//返回了堆上的引用,再c=a+b這種使用後,c是會析構的,但中間這個看不見的對象不會析構
119 }
120 String& String::operator+=(const String&rhs)
121 {
122     *this = *this + rhs;
123     //釋放掉原來的a,申請新空間
124     return *this;
125 }
126 bool String::operator==(const String&rhs)//比較是否相等,而不是相同
127 {
128     if (this->length != rhs.length) return false;
129     int i = 0;
130     for (; (*this).data[i] == rhs.data[i]; i++);
131     if (i != (rhs.length + 1)) return false;
132     else return true;
133 }
134 bool operator<(const String&lhs, const String&rhs)
135 {
136     return true;
137 }
138  ostream& operator<<(ostream& os, const String&rhs) //申明為友元函數。調用方式為cout<<s,申明為men fun,調用形式為s<<cout
139 {
140     os << rhs.data;//輸出null pointer會未定義行為
141     return os;
142 }
143  istream& operator>>(istream& is, String&rhs)
144  {//輸入一個字元串到字元指針,字元指針需要預先分配一定大小的空間,如何根據輸入的字元串調整空間大小
145      delete[]rhs.data;
146      rhs.data = new char[50]();
147      is.getline(rhs.data, 50);//最後位置自動置為'\0',所以最多存49個字元,可接收空格
148      rhs.length = strlen(rhs.data);
149      return is;
150  }
151 size_t String::size()
152 {
153     return length;
154 }
155 bool String::empty()
156 {
157     if (length == 0) return true;
158     else return false;
159 }
160 const char* String::c_str()//返回指向對象局部部分的引用,指針,能用來修改原對象嗎?
161 {//如果為空串,也要返回data
162     return data;
163 
164 }
165 String::~String()
166 {    //    析構會發生錯誤嗎?
167     //String創建時會new記憶體,當程式結束或局部String對象退出作用域時調用析構函數,釋放該記憶體
168     delete[]data; //如果String不是new出來的, 指針p指向它,delete p會導致錯誤,new出來的可以調用delete,這時會調用~String
169     data = NULL;
170 }
171 
172 //int  main()
173 //{
174 //    String s;
175 //    cout << s << endl;
176 //    cout << strlen(s.c_str()) << endl;
177 //    String s1 = "whah";
178 //    cout << s1 << endl;
179 //    String s2 = s1;
180 //    cout <<"s2 length:"<< s2.size() << endl;
181 //    s = s2; 
182 //    cout << "用s2賦值後的s: " << s << endl;
183 //    String s3(10, 'c');
184 //    cout << "字元填充初始化s3: " << s3 << " " << "s3 len= " << s3.size() << endl;
185 //    s3[0] = 'a';
186 //    cout << "下標修改s3後: " << s3 << endl;
187 //    String s4 = s2 + s3+"ad"; //支持連續的+
188 //    cout << s4 << endl;
189 //    String *sp = &s4;
190 //    cout << *sp << endl;
191 //    cout << strlen((*sp).c_str()) << endl;
192 //    String *q = new String(*sp);
193 //    cout << *q << endl;
194 //    delete q;
195 //
196 //    char *sq = const_cast<char*> (s4.c_str());
197 //    sq[0] = 'l';
198 //    cout << sq << endl;
199 //    cout << s4 << endl;
200 //    const char *cptr = s2.c_str();
201 //    string s5 = "";
202 //    string s6 = "\0";
203 //    cout << s5 << "**" << s6 << s5.size() << s6.size() << endl;
204 //    string str = "jadj";
205 //    char *sptr = const_cast<char *> (str.c_str());
206 //    sptr[0] = 'd';
207 //    cout << sptr << " " << str << endl;
208 //    String s7(s2);
209 //    s7 += s4;
210 //    cout << "s7: " << s7.size() << s7 << endl;
211 //    const String s8("daj");
212 //    //s8[0]; 對const對象的[]調用,不能用non-const menber版本的operator[],要提供 const char& operator[]() const重載版本
213 //    //s8 = "djwajk0";
214 //}
215 
216 int main()
217 {
218     string s2;
219     cin >> s2;
220     cout << s2 << endl;
221     String s, s1;
222     cin >> s >> s1;//用Enter間隔字元串,可接含有空格的字元串
223     cout << s <<"\n"<< s1 << endl;
224     cout << s1.size() << endl;
225 }
String類
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、NuGet搜索Npoi並安裝 2、添加引用將包引用進來 3、Controller里引用 4、使用 ...
  • 1 /// 2 /// 類說明:Assistant 3 /// 編 碼 人:蘇飛 4 /// 聯繫方式:361983679 5 /// 更新網站:http://www.sufeinet.com/thread-655-1-1.html 6 /// 7 using System; 8 using Sys... ...
  • <link href="~/Scripts/dropload/dropload.min.css" rel="stylesheet" /> <script src="~/Scripts/dropload/dropload.min.js"></script> ...
  • 首先,我們需要的是什麼東西? 用POST方式請求http,給網頁傳輸數據,網頁接收到數據之後,把數據存儲到資料庫中。 1.首先請求http,建立連接,把轉碼過的數據傳輸過去 2.網頁接收數據,在轉碼之後存儲到資料庫 3.網頁返回一個東西給傳輸方,表示我們已經接收到數據了 同樣,我們請求http也是用 ...
  • 繼承 繼承:就像遺傳一樣,繼承就是擁有父類的所有方法和屬性,並且能夠定義自己獨特的屬性和方法,對上面的類進行擴展。 可以什麼都不寫,直接繼承父類,如下: 上面代碼可以看出,首先定義了一個People的類,還有一個Man(People)類直接繼承People類。 下麵,我們在上面的Man()類中定義一 ...
  • Python3 迴圈語句本章節將為大家介紹Python迴圈語句的使用。Python中的迴圈語句有 for 和 while。Python迴圈語句的控制結構圖如下所示: while 迴圈Python中while語句的一般形式: 同樣需要註意冒號和縮進。另外,在Python中沒有do..while迴圈。 ...
  • Python 訪問字元串中的值Python 不支持單字元類型,單字元也在Python也是作為一個字元串使用。Python 訪問子字元串,可以使用方括弧來截取字元串,如下實例:實例(Python 3.0+) 以上實例執行結果: Python字元串更新 你可以對已存在的字元串進行修改,並賦值給另一個變數 ...
  • 加班到凌晨一點半很累很累,但是總覺得還是寫點東西 。 python運算符 程式還是需要多寫,多思考多變化。今天要睡覺,早上十點起,去公司加班。。。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...