C++學習筆記------Mstring類的實現
阿新 • • 發佈:2021-08-03
2.2 Mstring類的實現
Mstring類基本結構:
- push_back(), pop_back()
- is_full(), is_empty()
- 擴容revert()
- 輸出運算子過載、等號賦值運算子過載、[]運算子過載、比較運算子過載、加法(拼接)運算子過載等
class Mstring { private: char* _str; int _len;//容量 int _val_len;//資料長度(有效資料長度),不包括'\0' /* 以下成員方法不對外提供 */ bool is_full();//判滿 bool is_empty();//判空 void revert();//按照1.5倍進行擴容 public: Mstring(); Mstring(const char* str); Mstring(const Mstring& src); Mstring& operator=(/*this,*/const Mstring& src); //增加和刪除字元 void push_back(char c); char pop_back(); bool operator>(/*this, */const Mstring& src); bool operator==(const Mstring& src); Mstring operator+(/*this, */const Mstring& src); //->(箭頭運算子), * 解引用運算子 //普通物件呼叫該方法 char& operator[](int pos);//普通物件可以進行修改 //常物件呼叫該方法 char operator[](/*常物件指標*/int pos)const; //對常物件無法進行修改 ~Mstring() {//防止記憶體洩露 if (_str != NULL) { delete[]_str; } /*_str = NULL; 不用加嗎?*/ } friend ostream& operator<<(ostream& out, const Mstring& src); };
- 不對外部提供的成員方法的實現
實際上該部分並非要一開始實現,在完成push_back()和pop_back()時可以先使用,後面再考慮實現
bool is_full()//判滿 {//_len表示實際容量,_val_len表示有效字元(不包括'\0') return _len == _val_len+1; } bool is_empty() { return _val_len == 0;//判斷有效字元個數是否為0 } void revert()//按照1.5倍進行擴容 { if (_len==0)//呼叫預設建構函式時,_len是0,這時候接一個push_back()操作,就需要擴容 { _len = 10;//預設字元容量從10開始 } _len = _len + (_len >> 1);//右移除2,執行效率高 char* tmp = new char[_len];//開闢一塊新的記憶體 strcpy_s(tmp, _val_len+1, _str);//把已有內容進行拷貝,包括'\0' //釋放原來的記憶體,防止記憶體洩漏 if (_str != NULL) { delete[]_str; } _str = tmp; }
- 建構函式實現
Mstring()//在類構造之前一定要先構造它的所有成員 //:_str(),_len(),_val_len(),成員屬性的定義,一定會有成員屬性的定義或者初始化,只是大部分都是系統自動完成了 //const,引用以及成員物件(可能)需要手動實現 { _str = NULL; _len = 0; _val_len = 0; } Mstring(const char* str) { if (str == NULL) { _str = NULL; _len = 0; _val_len = 0; } _len = strlen(str) + 1;//+1表示'\0' _val_len = _len-1; _str = new char[_len]; strcpy_s(_str, _len, str); } Mstring(const Mstring& src)//拷貝構造 { _len = src._len; _val_len = src._val_len; //防止淺拷貝,拷貝構造哪來的釋放 _str = new char[_len]; strcpy_s(_str, _len, src._str); }
- push_back()和pop_back()的實現
void push_back(char c)
{
if (_str==NULL)//預設構造後,直接push_back()
{
_val_len = 1;//也就是實際容量從2開始才行
}
if (is_full())
{
revert();
}
if (_val_len == 0)
{
_val_len = 1;
}
_str[_val_len] = c;//把原來'\0'的位置覆蓋掉
_str[++_val_len] = 0;//後一位放'\0',_val_len加一
}
char pop_back()
{
if (is_empty()||_str==NULL)
{
return 0;
}
char c = _str[_val_len - 1];
_str[_val_len] = 0;
_val_len--;
return c;//不能返回區域性變數的引用和指標
}
- 等號賦值運算子過載實現
Mstring& operator=(/*this,*/const Mstring& src)
{
//防止自賦值,避免下一步釋放記憶體時出錯
if (&src != this)
{
return *this;
}
//防止記憶體洩漏
if (_str != NULL)
{
delete[]_str;
}
//防止淺拷貝
_len = src._len;
_val_len = src._val_len;
_str = new char[_len];
strcpy_s(_str, _len, src._str);
return *this;
}
- ==, >, +運算子過載實現
bool operator>(/*this, */const Mstring& src)
{//strcmp(str1, str2)--->相等返回0, str1>str2返回>0, str1>str2返回<0
return strcmp(_str, src._str)>0;
}
bool operator==(const Mstring& src)
{
return strcmp(_str, src._str) == 0;
}
//所謂加法,在這時拼接操作
Mstring operator+(/*this, */const Mstring& src)
{
Mstring tmp = *this;
//注意i=0, src._str[0]是第一個元素的位置,src._str[_val_len-2]是'\0'的位置
for (int i=0;i<src._val_len-1;i++) //(_val_len-1)---->'\0'的位置
{
tmp.push_back(src._str[i]);//push_back()有擴容處理
}
return tmp;
}
- [ ] 運算子過載實現
char& operator[](int pos)//普通物件可以進行修改
{
return _str[pos];
}
//常物件呼叫該方法
char operator[](/*常物件指標*/int pos)const //對常物件無法進行修改
{
return _str[pos];
}
- 輸出運算子過載實現
//注意在類中設定友元
ostream& operator<<(ostream& out, const Mstring& src)
{
for (int i=0;i<src._val_len;i++)
{
out << src._str[i];
}
return out;
}
測試:
int main()
{
Mstring str("12345");
cout << str<<endl;
for (int i = '0'; i < '9'; i++)
{
str.push_back(i);
cout << str << endl;
}
for (int i = 1; i < 9; i++)
{
cout << str.pop_back() << endl;
cout << str << endl;
}
return 0;
}
輸出結果: