C++:string類的實現

#include<iostream>
#include<string.h>
#include<assert.h>
#include<stdio.h>

class String
{
public:
    //構造函數
    String(const char *str="")
        :_size(strlen(str))
        ,_capacity(_size)
    {
        _str = new char[_size+1];
        strcpy(_str,str);
    }
    void Swap(String& s)
    {
        std::swap(_str,s._str);
        std::swap(_size,s._size);
        std::swap(_capacity,s._capacity);
    }
    //拷貝構造
    String(const String& s)
        :_str(NULL)
    {
        String tmp(s._str);
        this->Swap(tmp);
    }
    //賦值運算符的重載
    String& operator=(String s)
    {
        this->Swap(s);
        return *this;
    }
    //析構函數
    ~String()
    {
        if(_str)
        {
            delete[] _str;
            _str = NULL;
        }
    }
    //求string的字符個數
    size_t Size()
    {
        return _size;
    }
    //求string的容量
    size_t Capacity()
    {
        return _capacity;
    }
    //求string的內容
    char *Str()
    {
        return _str;
    }
    //判斷string是否爲空
    bool Empty()
    {
        return _size == 0;
    }
    //[]操作符的重載
    char& operator[](size_t pos)
    {
        return _str[pos];
    }
    //擴容,只會改變_capacity的大小
    void Reserve(size_t n)
    {
        Expand(n);
    }
    //可能會同時改變_size和_capacity
    //並且還會進行初始化(缺省初始化爲'\0')
    void Resize(size_t n,char ch = '\0')
    {
        if(n <= _size)
        {
            //此時因爲是縮小了或者不變所以不用改變_capacity的值
            _str[n] = '\0';
            _size = n;
        }
        else
        {
            if(n > _capacity)
            {
                //此時n超過了容量的大小因此需要擴容
                Expand(n);
            }
            for(size_t i = _size;i < n;++i)
            {
                _str[i] = ch;
            }
            _str[n] = '\0';
            _size = n;
        }
    }
    //擴容函數(這裏涉及到一個問題就是如何擴容??附在代碼後面)
    void Expand(size_t n)
    {
        if(n > _capacity)
        {
            char *tmp = new char[n+1];
            strcpy(tmp,_str);
            delete[] _str;
            _str = tmp;
            _capacity = n;
        }
    }
    //尾插函數
    void PushBack(char ch)
    {
        //方法1:
       // if(_size == _capacity)
       // {
       //     Expand(_capacity*2);
       // }
       // _str[_size] = ch;
       // _str[_size+1] = '\0';
       // ++_size;
        //方法2:可直接調用實現的Insert()函數
        Insert(_size,ch);
    }
    //在string的後面追加一個字符串
    void Append(const char *str)
    {
        size_t len = strlen(str);
        if(_size+len >_capacity)
        {
            Expand(_size+len);
        }
        strcpy(_str+_size,str);//接着_str的末尾開始往後拷貝
        _size += len;
    }
    //某個位置插入字符
    void Insert(size_t pos,char ch)
    {
        assert(pos <= _size);
        if(_capacity == _size)
        {
            //此時已經相等,如果在想插入一個元素則空間肯定不夠,
            //需要擴容
            Expand(_capacity*2);
        }
        int end = _size;
        while(end >= (int)pos)
        {
            //把包括pos位置在內的往後所有元素依次往後移動一個位置
            _str[end+1] = _str[end];
            --end;
        }
        //移動完成以後,pos位置就空出來了,將待插入的元素插入
        _str[pos] = ch;
        ++_size;
    }
    //某個位置插入字符串
    void Insert(size_t pos,const char *str)
    {
        assert(pos <= _size);
        size_t len = strlen(str);
        if(_size + len > _capacity)
        {
            Expand(_size+len);
        }
        int end = _size;
        while(end >= (int)pos)
        {
            _str[end+len] = _str[end];
            --end;
        }
        strncpy(_str+pos,str,len);
        //使用strncpy不會將待插入的字符串的'\0'也拷貝進目標字符串
    }
    //s1+="hello" +=運算符重載,與Append函數功能相同
    String& operator+=(const char *str)
    {
        this->Append(str);
        return *this;
    }
    //s1+=s2 兩個string類的+=實現
    String operator+=(const String& s)
    {
        *this += s._str;//相當於this->operator+=(this,s._str);
        return *this;
    }
    //s1+"hello"
    String operator+(const char *str)
    {
        String ret(*this);
        ret.Append(str);
        return ret;
    }
    //s1+s2
    String operator+(const String s)
    {
        return *this+s._str;
    }
    //尾刪
    void PopBack()
    {
        assert(_size > 0);
        --_size;
        _str[_size] = '\0';
    }
    //刪除某一位置往後的len個元素
    void Erase(size_t pos,size_t len)
    {
        assert(pos < _size);
        if(pos+len >= _size)
        {
            //此種情況就是將pos往後的所有都刪掉
            _str[pos] = '\0';
            _size = pos;
        }
        else
        {
            strcpy(_str+pos,_str+pos+len);
            _size -= len;
        }
    }
    //在string中查找是否存在某一個字符,若存在返回下標
    size_t Find(char ch)
    {
        for(size_t i = 0;i < _size;i++)
        {
            if(_str[i] == ch)
            {
                return i;
            }
        }
        //這裏的npos是string類中的一個公有的成員變量(值爲-1)
        //返回這個就說明沒有找到
        return npos;
    }
    //在string中查找是否存在某一個子串,類似於strstr函數
    size_t Find(const char *sub) const
    {
        if(sub == NULL)
        {
            return npos;
        }
        char *ret = _str;
        while(*ret)
        {
            char *cur_tmp = (char *)sub;
            char *str_tmp = ret;
            while(*str_tmp && cur_tmp && *str_tmp == *cur_tmp)
            {
                str_tmp++;
                cur_tmp++;
            }
            if(*cur_tmp == '\0')
            {
                //找到了,返回匹配到的子串往後的字符串
                //如查找abc在dabcjd23dabce中是否存在,
                //結果返回abcjd23dabce這個字符串
                return ret-_str;
            }
            else
            {
                ret++;
            }
        }
        return npos;
    }
    bool operator<(const String& s) const
    {
        const char* str1 = _str;
        const char* str2 = s._str;
        while(*str1 && *str2)
        {
            if(*str1 < *str2)
                return true;
            else if(*str1 > *str2)
                return false;
            else
            {
                ++str1;
                ++str2;
            }
        }
        if(*str1 == '\0' && *str2 != '\0')
        {
            //str1字符串比str2這個字符串要短
            return true;
        }
        else
        {
            return false;
        }
    }
    bool operator<=(const String& s) const
    {
        return *this<s || *this==s;
    }
    bool operator>(const String& s) const
    {
        return !(*this<=s);
    }
    bool operator>=(const String& s) const
    {
        return !(*this<s);
    }
    bool operator==(const String& s) const
    {
        const char *str1 = _str;
        const char *str2 = s._str;
        while(*str1 && *str2)
        {

            if(*str1 != *str2)
            {
                return false;
            }
            else
            {
                ++str1;
                ++str2;
            }
        }
        if(*str1 == '\0' && *str2 == '\0')
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    bool operator!=(const String& s) const
    {
        return !(*this==s);
    }
private:
    char *_str;
    size_t _size;
    size_t _capacity;
public:
    static size_t npos;
};
size_t String::npos = -1;


void Test()
{
    String s("hello");
    //拷貝構造函數測試
    String s1(s);
    std::cout<<s1.Str()<<std::endl;
    //賦值運算符重載函數測試
    String s2;
    s2 = s;
    std::cout<<s2.Str()<<std::endl;
    //[]運算符重載函數測試
    std::cout<<s[0]<<std::endl;
    //PushBack函數測試
    s.PushBack(' ');
    std::cout<<s.Str()<<std::endl;
    //Append函數測試
    s.Append("world");
    std::cout<<s.Str()<<std::endl;
    //Insert函數測試
    s.Insert(11,'O');
    std::cout<<s.Str()<<std::endl;
    s.Insert(1,'H');
    std::cout<<s.Str()<<std::endl;
    //s.Insert(15,'&');
    //std::cout<<s.Str()<<std::endl;
    //PopBack函數測試
    s.PopBack();
    std::cout<<s.Str()<<std::endl;
    //Erase函數測試
    s.Erase(2,3);
    std::cout<<s.Str()<<std::endl;
    s.Erase(5,10);
    std::cout<<s.Str()<<std::endl;
    //Find函數測試
    size_t ret = s.Find('a');
    //size_t ret = s.Find('h');
    if(ret != String::npos)
    {
        printf("找到了\n");
    }
    else
    {
        printf("沒找到\n");
    }
}
int main()
{
    Test();
    return 0;
}

問題1:如何擴容???

答:呈2倍的增長。但不是一定就是2倍增的,看情況(Linux下是2倍,vs下是1/2倍)。那麼爲什麼2倍的增比較好?因爲如果增多了就很有可能造成空間的極大浪費,而增2倍即有了空間也不至於過於頻繁的去進行增容。

問題2:Reverse()和Resize()的區別???

這個在代碼的兩個函數實現處的註釋中已經說明

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章