簡單的string類的模擬實現

gogogo_sky發表於2017-05-25

綜述:c++標準庫提供了一個字串型別string ,該型別可以直接定義一個字串物件,並且對字串進行各種操作;以下是本人根據c++標準庫中的string類,簡單的模擬實現該類;
先看cpulspuls中string類的成員函式:
這裡寫圖片描述
其中我只實現圖中列出函式原型的幾個成員函式:
(1)實現之前先看看這寫函式及其過載函式是什麼意思:
測試程式碼:

#include<iostream>
using namespace std;
#include<string>
int main()
{
    string str1("12345");
    cout<<"str1:"<<str1<<endl;
    str1.push_back('w');
    cout<<"str1.push_back('w'):"<<str1<<endl;
    cout<<"str1[0]:"<<str1[0]<<"\nstr[1]:"<<str1[1]<<endl;
    string str2("abcde");
    cout<<"str2:"<<str2<<endl;
    str1+=str2;
    cout<<"str1+=str2:"<<str1<<endl;
    str1+="www";
    cout<<"str1+=www:"<<str1<<endl;
    str1+='M';
    cout<<"str1+='M':"<<str1<<endl;
    cout<<endl;
    cout<<endl;


    string str3("123456");
    string str4("www");
    cout<<"str3:"<<str3<<"\nstr4:"<<str4<<endl;
    str3.insert(3,str4);
    cout<<"str3.insert(3,str4):"<<str3<<endl;

    string str5("abcdef");
    cout<<"str5:"<<str5<<endl;
    str3.insert(3,str5,2,3);
    cout<<"str3.insert(3,str5,2,3):"<<str3<<endl;
    cout<<endl;
    cout<<endl;
    cout<<"str5:"<<str5<<endl;
    str5.insert(4,"789456",3);
    cout<<"str5.insert(4,\"789456\",3):"<<str5<<endl;
    cout<<endl;
    cout<<endl;
    string str6("hanxu");
    cout<<"str6:"<<str6<<endl;
    str6.insert(3,"LOVE");
    cout<<"str6.insert(3,\"LOVE\"):"<<str6<<endl;

    cout<<endl;
    cout<<endl;
    string str7("smth");
    cout<<"str7:"<<str7<<endl;
    str7.insert(2,2,'o');
    cout<<"str7.insert(2,'o',2):"<<str7<<endl;
    return 0;
}

圖解:
這裡寫圖片描述
三、模擬實現


//模擬實現c++標準庫中的string類

#include<iostream>
using namespace std;
#include<string.h>
class String
{
friend ostream& operator<<(ostream& os,String& s);
    //類的預設成員函式
public:
    String(const char* str="")//構造
        :_capacity(strlen(str)+1)
        ,_sz(strlen(str))
        ,_str(new char[strlen(str)+1])
    {
          cout<<"String(const char* str=\"\");"<<endl;
          strcpy(_str,str);
    }
    String(const String& s)//拷貝構造
        :_capacity(strlen(s._str)+1)
        ,_sz(s._sz)
        ,_str(new char[strlen(s._str)+1])
    {
        cout<<"String(const Strig& s);"<<endl;
        strcpy(_str,s._str);
    }
    /*String& operator=(String s)//賦值操作符過載---現代寫法(不用引用傳參)
    {
        cout<<"String& operator=(String s)"<<endl;
        std::swap(_str,s._str);
        _capacity=strlen(s._str)+1;
        _sz=s._sz;
        return *this;
    }*/
    String& operator=(const String& s)//賦值操作符過載---常規寫法(引用傳參)
    {
        cout<<"String& operator=(const String& s);"<<endl;
        if (this!=&s)
        {
            delete[] _str;
            _str=new char[strlen(s._str)+1];
            strcpy(_str,s._str);
        }
        return *this;
    }
    ~String()//析構
    {
        cout<<"~String();"<<endl;
        if (NULL!=_str)
        {
            delete[] _str;
            _str=NULL;
        }
        _capacity=0;
        _sz=0;
    }
    //類的操作成員函式
public:
     void push_back(const char c);//給物件後面新增一個字元
     char& operator[] ( size_t pos );//取物件的下標元素
     const char& operator[](size_t pos)const;//取字串的下標元素
     String& operator+= ( const String& str );//給一個物件本身追加另一個物件
     String& operator+= ( const char* s );//給一個物件本身追加一個字串
     String& operator+= ( char c );//給一個物件本身追加一個字元

     //以下函式的位置pos1都是從0計數開始
     String& insert ( size_t pos1, const String& str );//在一個字串的pos1位置插入字串str
     String& insert ( size_t pos1, const String& str, size_t pos2, size_t n );//在一個字串的pos1位置插入字串str前n位組成的字串
     String& insert ( size_t pos1, const char* s, size_t n);//在一個字串的pos1位置插入字串s前n位組成的字串
     String& insert ( size_t pos1, const char* s );//在一個字串的pos1位置插入字串s
     String& insert ( size_t pos1, size_t n, char c );//在一個字串的pos1位置插入n個字元c
private:
    //由於檢查並調整容量,只是在成員函式內部呼叫,所有經該函式定義為私有成員函式,不對外提供介面;體現c++的封裝特性,使該類變得安全
     void  CheakCapacty(size_t n)//檢查容量,並調整容量
     {
         if (_sz+1+n>=_capacity)
         {
             _capacity=_capacity*2+10;
             char* tmp=new char[_capacity];
             strcpy(tmp,_str);
             delete[] _str;
             _str=tmp;
         }
     }
private:
    size_t _capacity;//字串當前的容量
    size_t _sz;//字串實際的字元個數(不包含'\0')
    char* _str;//字串
};

void String::push_back(const char c)//給字串後面新增一個字元c
{
      CheakCapacty(1);
      _str[_sz++]=c;
      _str[_sz]='\0';
}
const char& String::operator[](size_t pos)const//取字串的下標元素
{
     return _str[pos];
}
char& String::operator[](size_t pos)//取字串的下標元素
{
     return _str[pos];
}

String& String::operator+= (const String& str )//給一個字串本身後面加上一個字串
{
     CheakCapacty(strlen(str._str));
     strcat(_str,str._str);//字串追加
     _sz+=str._sz;
     return *this;
}
String& String::operator+= ( const char* s )//給一個字串本身後面加上一個字串
{
     CheakCapacty(strlen(s));
     strcat(_str,s);
     _sz+=strlen(s);
     return *this;
}
String& String::operator+=( char c )//給一個字串本身後面加上一個字元
{
    CheakCapacty(1);
    _str[_sz++]=c;
    _str[_sz]='\0';
    return *this;
}

String& String::insert ( size_t pos1, const String& str )//從一個字串的pos位置開始插入字串str
{
    if (_str==NULL||str._str==NULL)
    {
        return *this;
    }
    if (pos1>=0&&pos1<=strlen(_str))//'\0'位置也可以插入
    {  
        CheakCapacty(strlen(str._str));//調整容量
        char* tmp=new char[strlen(_str)-pos1+2];//開闢一段新空間儲存pos1位及其以後的字元
        strcpy(tmp,_str+pos1);//把字串pos1位置及其後的字串賦值到臨時空間
        strcpy(_str+pos1,str._str);//將要插入的字串複製到對應的其實位置
        strcpy(_str+(pos1+strlen(str._str)),tmp);//將之前臨時變數儲存的原字串pos1位置之後的字串新增到插入以後的部分!
        delete[] tmp;
    }
    return *this;
}


String& String::insert ( size_t pos1, const String& str, size_t pos2, size_t n )//在一個字串的pos1位置插入str字串的pos2位置及其後面的n個字元
{
    if (_str==NULL||(str._str+pos2)==NULL)
    {
        return *this;
    }
    if (pos1>=0&&pos1<=strlen(_str)&&pos2>=0&&pos2<=strlen(str._str))
    {
        CheakCapacty(strlen(str._str));//調整容量
        char* tmp=new char[strlen(_str)-pos1+2];//開闢一段新空間儲存pos1位及其以後的字元
        strcpy(tmp,_str+pos1);//把字串pos1位置及其後的字串賦值到臨時空間
        strncpy(_str+pos1,str._str+pos2,n);//將要插入的n個字元複製到對應的其實位置
        strcpy(_str+(pos1+n),tmp);//將之前臨時變數儲存的原字串pos1位置之後的字串新增到插入以後的部分!
        delete[] tmp;
    }
    return *this;
}
String& String::insert ( size_t pos1, const char* s, size_t n)//在一個字串的pos1位置插入字串s前n位組成的字串
{
    if (_str==NULL||s+n==NULL)
    {
        return *this;
    }
    if (pos1>=0&&pos1<=strlen(_str))//'\0'位置也可以插入
    {  
        CheakCapacty(n);//調整容量
        char* tmp=new char[strlen(_str)-pos1+2];//開闢一段新空間儲存pos1位及其以後的字元
        strcpy(tmp,_str+pos1);//把字串pos1位置及其後的字串賦值到臨時空間
        strncpy(_str+pos1,s,n);//將要插入的字串複製到對應的其實位置
        strcpy(_str+(pos1+n),tmp);//將之前臨時變數儲存的原字串pos1位置之後的字串新增到插入以後的部分!
        delete[] tmp;
    }
    return *this;
}
String& String::insert ( size_t pos1, const char* s )//在一個字串的pos1位置插入字串s
{
    if (_str==NULL||s==NULL)
    {
        return *this;
    }
    if (pos1>=0&&pos1<=strlen(_str))//'\0'位置也可以插入
    {  
        CheakCapacty(strlen(s));//調整容量
        char* tmp=new char[strlen(_str)-pos1+2];//開闢一段新空間儲存pos1位及其以後的字元
        strcpy(tmp,_str+pos1);//把字串pos1位置及其後的字串拷貝到臨時空間
        strcpy(_str+pos1,s);//將要插入的字串複製到對應的其實位置
        strcpy(_str+(pos1+strlen(s)),tmp);//將之前臨時變數儲存的原字串pos1位置之後的字串新增到插入以後的部分!
        delete[] tmp;
    }
    return *this;
}
String& String::insert ( size_t pos1, size_t n, char c )//在一個字串的pos1位置插入n個字元c
{
    if (_str==NULL||n<=0)
    {
        return *this;
    }
    if (pos1>=0&&pos1<=strlen(_str))//'\0'位置也可以插入
    {  
        CheakCapacty(n);//調整容量
        char* tmp=new char[strlen(_str)-pos1+2];//開闢一段新空間儲存pos1位及其以後的字元
        strcpy(tmp,_str+pos1);//把字串pos1位置及其後的字串拷貝到臨時空間
        while(n--)
        {
            _str[pos1++]=c;
        }
        strcpy(_str+(pos1+n+1),tmp);
        delete[] tmp;
    }
    return *this;
}

ostream& operator<<(ostream& os,String& s)
{
    os<<s._str;
    return os;
}
int main()
{
    ////1.四個預設建構函式測試
    //String s1("1234");
    //cout<<"s1:"<<s1<<endl;
    //String s2("56789abcd");
    //cout<<"s2:"<<s2<<endl;
    ////String s3;
    ////cout<<s3<<endl;
    ////s3=s2;
    ////cout<<s3<<endl;


 //   //2.push_back和operator[]測試
    ////cout<<s1[0]<<"->"<<s1[1]<<"->"<<s1[2]<<endl;
    ////s1.push_back('W');
    ////cout<<s1<<endl;

    ////3.operator+=()函式測試
    ////s1+=s2;//String& String::operator+= (const String& str )
 //   //s1+="abcd";//String& String::operator+= ( const char* s )
 //   //s1+='w';//String& String::operator+=( char c )
    ////cout<<s1<<endl;

    ////4.insert()函式測試
    ////s1=s1.insert(2,s2);
    ////cout<<"s1.insert(2,s2):"<<s1<<endl;
    ////s1=s1.insert(2,s2,3,4);
    ////cout<<"s1.insert(2,s2,3,4):"<<s1<<endl;
 //   //s2=s2.insert(4,"HKLM",2);
 //   //cout<<"s2=s2.insert(4,\"HKLM\",2):"<<s2<<endl;
    //s2=s2.insert(5,"HMWKT");
    //cout<<"s2=s2.insert(5,\"HMWKT\"):"<<s2<<endl;
    ////s2=s2.insert(5,3,'M');
    ////cout<<"s2=s2.insert(5,3,'M'):"<<s2<<endl;



    String str1("12345");
    cout<<"str1:"<<str1<<endl;
    str1.push_back('w');
    cout<<"str1.push_back('w'):"<<str1<<endl;
    cout<<"str1[0]:"<<str1[0]<<"\nstr[1]:"<<str1[1]<<endl;
    String str2("abcde");
    cout<<"str2:"<<str2<<endl;
    str1+=str2;
    cout<<"str1+=str2:"<<str1<<endl;
    str1+="www";
    cout<<"str1+=www:"<<str1<<endl;
    str1+='M';
    cout<<"str1+='M':"<<str1<<endl;
    cout<<endl;
    cout<<endl;


    String str3("123456");
    String str4("www");
    cout<<"str3:"<<str3<<"\nstr4:"<<str4<<endl;
    str3.insert(3,str4);
    cout<<"str3.insert(3,str4):"<<str3<<endl;

    String str5("abcdef");
    cout<<"str5:"<<str5<<endl;
    str3.insert(3,str5,2,3);
    cout<<"str3.insert(3,str5,2,3):"<<str3<<endl;
    cout<<endl;
    cout<<endl;
    cout<<"str5:"<<str5<<endl;
    str5.insert(4,"789456",3);
    cout<<"str5.insert(4,\"789456\",3):"<<str5<<endl;
    cout<<endl;
    cout<<endl;
    String str6("hanxu");
    cout<<"str6:"<<str6<<endl;
    str6.insert(3,"LOVE");
    cout<<"str6.insert(3,\"LOVE\"):"<<str6<<endl;

    cout<<endl;
    cout<<endl;
    String str7("smth");
    cout<<"str7:"<<str7<<endl;
    str7.insert(2,2,'o');
    cout<<"str7.insert(2,'o',2):"<<str7<<endl;
    return 0;

    return 0;
}

三、模擬實現的測試程式碼和(1)中測試部分程式碼完全相同,執行結果也相同,證明本次模擬達到了c++標準庫的實現要求,模擬正確;
這裡寫圖片描述

接下來的文章,用物件導向的思想,利用c++語言實現順序表和雙連結串列

相關文章