1. 程式人生 > 其它 >C++學習筆記------Mstring類的實現

C++學習筆記------Mstring類的實現

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;
}

輸出結果: