C++ string容器類實現

     最近想學習一下C++ STL中容器類的實現,就先研究最簡單的string容器類,通過學習簡單的,達到管中窺豹,舉一反三的目的,話不多說,直接來乾貨,寫得不好,望大家多多交流和指教。

代碼如下:

<span style="font-size:18px;">// MyString.cpp : 定義控制檯應用程序的入口點。
//
/*****************************************
**功能:自己實現C++ STL的string容器類
**作者:謝凡凡
**時間:2015-07-21  02:20
*****************************************/
#include "stdafx.h"
#include <iostream>
#include <iomanip>                                       //後邊用到函數setw設置域寬,所以包含該頭文件

using namespace std;

//自己嘗試寫的一個string容器類
class MyString
{
    friend ostream& operator<<(ostream&,MyString&);      //輸出運算符重載,友元函數
    friend istream& operator>>(istream&,MyString&);      //輸入運算符重載
public:
    MyString(const char* str = NULL);                   //默認構造函數,含有一個默認參數
    MyString(const MyString& other);                    //拷貝構造函數,拷貝了數據,所以說深拷貝
    MyString& operator=(const MyString& other);         //重載賦值運算符
    MyString operator+(const MyString& other) const;     //重載加號運算符
    bool operator==(const MyString& );                  //operator==
    bool operator<(const MyString& );                   //operator<
    char& operator[](int);                     //operator[]
    size_t size() {return strlen(m_data);}
    MyString& append(const MyString& other);             //在尾部插入
    MyString& insert(unsigned int ipos,const char *);    //任意位置插入
    MyString& replace(unsigned int ipos,unsigned int num,const char *);       //替換操作
    MyString& erase(unsigned int start,unsigned int final);                   //刪除函數
    int find(const char* stem,int ipos = 0);                                  //查找函數
    int find_first_of(const char* stem,int ipos = 0);                         //查找字符串中第一個在指定串中出現的字符位置
    int rfind(const char *stem,int ipos = -1);                                     //反向查找,從左往右數ipos位做爲起始的位置,然後從右往左匹配,找到第一個返回位置
    int npos;                                           //查詢標誌  表示字符串查詢失敗
    //下邊寫迭代器類
    class Iterator
    {
        char *init;
    public:
        inline Iterator(char* init) {this->init = init;}           //構造函數
        inline bool operator!=(Iterator& it) {return this->init != it.init;}     //迭代器的幾個運算符重載
        inline void operator++(int){init = init + 1;}
        inline char operator*() {return *init;}
    };
    char* Begin() {return m_data;}                        //獲得迭代器的起始位置
    char* End(){return m_end;}                          //獲得迭代器的尾後位置
    ~MyString();                                        //析構函數
private:
    char* m_data;                                       //指向動態內存的指針
    char* m_end;                                        //尾後指針
};

inline MyString::MyString(const char* str)              //默認構造函數設爲內聯  不掉用  直接替換
{
    if (!str)
    {
        m_data =NULL;
        m_end = NULL;
    }
    else
    {
        m_data = new char[strlen(str)+1];
        m_end = m_data + strlen(str);                  //尾後迭代器位置
        strcpy(m_data,str);
    }
    npos = -1;
}

inline MyString::MyString(const MyString& other)       //拷貝函數
{
    if (!other.m_data)                                 //在類的成員函數內可以訪問同種對象的私有數據(同種類是友元關係)
    {
        m_data = NULL;
        m_end = NULL;
    }
    else
    {
        m_data = new char[strlen(other.m_data)+1];
        m_end = m_data + strlen(other.m_data);
        strcpy(m_data,other.m_data);
    }
    npos = -1;
}

inline MyString& MyString::operator=(const MyString& other)     //賦值運算符
{
    if (this != &other)                                         //注意,賦值運算符考慮自賦值
    {
        delete [] m_data;
        m_end = m_data;
        if (!other.m_data)
        {
            m_data = NULL;
            m_end = NULL;
        }
        else
        {
            m_data = new char[strlen(other.m_data)+1];
            m_end = m_data + strlen(other.m_data);
            strcpy(m_data,other.m_data);
        }
    }
    return *this;                                             //this指針的引用爲類對象
}

inline MyString MyString::operator+(const MyString& other)const    //加號重載
{
    //考慮多種情況
    MyString newString;               //加號重載,返回一個值,所以用一個臨時變量返回
    if (!other.m_data)
    {
        newString = *this;
    }
    else if (!m_data)
    {
        newString = other;
    }
    else
    {
        newString.m_data = new char[strlen(m_data) + strlen(other.m_data) +1];
        newString.m_end = newString.m_data + strlen(m_data) + strlen(other.m_data);
        strcpy(newString.m_data,m_data);
        strcat(newString.m_data,other.m_data);
    }
    return newString;
}

inline bool MyString::operator==(const MyString& other)
{
    if (strlen(other.m_data) != strlen(m_data))
    {
        return false;
    }
    else
    {
        return strcmp(other.m_data,m_data)?false:true;
    }
}

inline bool MyString::operator<(const MyString& other)                   //operator<
{
    if (strlen(m_data) == 0 && strlen(other.m_data) != 0)
    {
        return true;
    }
    else if (strlen(m_data) != 0 && strlen(other.m_data) == 0)
    {
        return false;
    }
    else if (strlen(m_data) == 0 && strlen(other.m_data) == 0)          //表示兩個都爲空
    {
        return false;
    }

    int iIndex = 0;
    while (m_data[iIndex] && other.m_data[iIndex])              //相同長度逐個比較字符
    {
        if (m_data[iIndex] < other.m_data[iIndex])
        {
            return true;
        }
        else if (m_data[iIndex] > other.m_data[iIndex])
        {
            return false;
        }
        else
        {
            ++iIndex;
        }
    }
    if (!m_data[iIndex] && other.m_data[iIndex])                 //第一個字符串比第二個字符串短 但前邊相同  eg: xiefanfan xiefanfanaa
    {
        return true;
    }
    else
    {
        return false;
    }	
}

inline char& MyString::operator[](int num)
{
    if (num < 0 || num >= strlen(m_data))
    {
        cout<<"string subscript out of range"<<endl;
    }
    if (num>=0 && num<strlen(m_data))
    {
        return m_data[num];
    }
}

ostream& operator<<(ostream& os,MyString& mstem)            //友元函數,表示該函數不是該類的成員,但是可以操作類的私有數據
{
    os<<mstem.m_data;                                       //不要添加格式控制符,只做輸出
    return os;                                              //return支持連續<<
}

istream& operator>>(istream& is,MyString& mstem)
{
    char temp[255];                                         //臨時緩衝空間
    is>>setw(255)>>temp;
    mstem = temp;                                           //使用賦值運算符
    return is;											    //return支持連續>>
}

MyString::~MyString()                                      //析構函數
{
    if (m_data)
    {
        delete [] m_data;
        m_data = NULL;
        m_end = NULL;
    }
}

MyString& MyString::append(const MyString& other)             //在尾部插入  參考operator+函數
{
    MyString newString;                                       //申請一個臨時空間  將原始字符串保存起來
    if (!other.m_data)
    {
        return *this;
    }
    else if (!m_data)
    {
        m_data = new char[strlen(other.m_data) + 1];
        m_end = m_data + strlen(other.m_data);
        strcpy(m_data,other.m_data);
        return *this;
    }
    else
    {
        newString = *this;
        m_data = new char[strlen(newString.m_data) + strlen(other.m_data) +1];
        m_end = m_data + strlen(newString.m_data) + strlen(other.m_data);
        strcpy(m_data,newString.m_data);
        strcat(m_data,other.m_data);
        return *this;
    }
}
MyString& MyString::insert(unsigned int ipos,const char *stem)            //任意位置插入函數
{
    MyString newString;
    int iIndex;
    if (ipos >= 0 && ipos < strlen(m_data))                               //ipos在範圍內部
    {
        newString.m_data = new char[strlen(m_data) + strlen(stem) +1];     //申請空間
        newString.m_end = m_data + strlen(m_data) + strlen(stem);
        for (iIndex = 0;iIndex < strlen(m_data) + strlen(stem);++iIndex)
        {
            if (iIndex < ipos)                                             //拷貝原始串  ipos前的數據                        
            {
                newString.m_data[iIndex] = m_data[iIndex];
            }
            else
            {
                if (iIndex >= ipos && iIndex < (ipos + strlen(stem)))     //添加子串
                {
                    newString.m_data[iIndex] = stem[iIndex - ipos];
                }
                else                                                      //添加原來字符串後邊的串
                {
                    newString.m_data[iIndex] = m_data[iIndex - strlen(stem)];
                }
            }
        }
        newString.m_data[iIndex] = NULL;                                      //最後一位置空 表示字符串結束
    }
    *this = newString;
    return *this;
}

MyString& MyString::replace(unsigned int ipos,unsigned int num,const char *stem)            //替換操作                                   
{
    MyString newString;                                                   //臨時緩存字符串
    int iIndex;
    if (ipos >= 0 && ipos < strlen(m_data) )
    {
        int iNewlen = strlen(m_data) + strlen(stem) - num;                //新的長度
        newString.m_data = new char[iNewlen + 1];
        newString.m_end = m_data + iNewlen;
        for (iIndex = 0;iIndex < iNewlen;++iIndex)
        {
            if (iIndex < ipos)                                             //拷貝ipos索引前的字符
            {
                newString.m_data[iIndex] = m_data[iIndex];
            }
            else if (iIndex >= ipos && iIndex < ipos + strlen(stem))       //拷貝替換的串
            {
                newString.m_data[iIndex] = stem[iIndex - ipos];
            }
            else                                                           //拷貝原串剩餘的部分
            {
                newString.m_data[iIndex] = m_data[iIndex - strlen(stem) + num];       
            }
        }
    }
    newString.m_data[iIndex] = '\0';                                   //字符串最後置爲0                
    *this = newString;  
    return *this;
}
/////////////////////////////此處應該用的迭代器/////////////////////////////////////////////
MyString& MyString::erase(unsigned int start,unsigned int final)                   //刪除函數
{
    if (start >= 0 && start < strlen(m_data) && final >= 0 && final < strlen(m_data) && start <= final)
    {
        int iIndex;
        for (iIndex = final;iIndex < strlen(m_data);++iIndex )
        {
            m_data[iIndex - final + start] = m_data[iIndex];                       //後邊覆蓋前邊
        }
        m_data[iIndex - (final - start)] = '\0';
        m_end = m_data + iIndex - (final - start);
    }
    return *this;
}

int MyString::find(const char* stem,int ipos )                                  //字串查找函數  
{
    if (ipos + strlen(stem) > strlen(m_data))                                      //超出範圍
    {
        return npos;
    }
    for (int iIndex = ipos;iIndex < strlen(m_data) - strlen(stem);++iIndex)        //在長的串中匹配指定的串  若要快速匹配  可以用KMP算法
    {
        int jval = 0;
        while (stem[jval] && stem[jval] == m_data[iIndex + jval])                 //逐位匹配
        {
            jval++;
        }
        if (jval >= strlen(stem))
        {
            return iIndex;
        }
    }
    return npos;
}

int MyString::find_first_of(const char* stem,int ipos)                         //查找字符串中第一個在指定串中出現的字符位置
{
    int length = strlen(m_data);
    int iIndex;
    for ( iIndex = 0;iIndex < length;++iIndex)
    {
        for (int iIndex1 = 0;iIndex1 < strlen(stem);++iIndex1)
        {
            if (m_data[iIndex] == stem[iIndex1])                         //如果匹配上一個字符,返回座標
            {
                return iIndex;
            }
        }
    }
    if (iIndex >= length)
    {
        return npos;
    }
}
int MyString::rfind(const char *stem,int ipos)                                 //反向查找
{
    if (ipos == npos)
    {
        ipos = strlen(m_data);
    }
    for (int iIndex = ipos;iIndex >= 0;--iIndex)
    {
        int slen = strlen(m_data);                         //原串長度
        int slen1 = strlen(stem);                          //匹配串長度
        if ((slen - iIndex) >= slen1)                      //當前字符後邊字符數大於等於帶匹配串
        {
            int tem = 0;
            while (m_data[iIndex + tem] == stem[tem] && tem < slen1)        //逐項匹配
            {
                ++tem;
            }
            if (tem >= slen1)
            {
                return iIndex;
            }
        }
    }
    return npos;                                             //如果上邊沒有匹配上,表示不存在匹配項
}


int _tmain(int argc, _TCHAR* argv[])
{
    MyString str("fasfd");
    str.erase(0,2);
    MyString::Iterator start = str.Begin();
    MyString::Iterator end = str.End();
    while(start != end)
    {
        cout<<*start<<endl;
        start++;
    }

    return 0;
}</span>
    每一個函數經過測試,功能基本上跑通了,但是壓力測試可能過不了。

    自我總結需要改進的地方:

    (1)每一次大小改變都重新申請內存,導致效率不高,同時造成內存碎片。[改進:申請一塊內存,多申請一些,多餘的內存作爲保留字節]

    (2)string的成員函數參數大部分都是字符串類型,應該還有輸入迭代器類型的很多重載函數,我也沒有實現。

    (3)有部分成員函數爲實現,比如查找只實現了三個,還有像capacity(),reserve()沒有實現,也可以添加實現。

    (4)函數加保護,超出範圍是拋出異常還是報錯,沒實現。[本想拋出異常的,但是還不太會,就沒做]

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