C++關(guān)于string類的模擬實(shí)現(xiàn)-創(chuàng)新互聯(lián)

文章目錄
  • 一、string類的模擬實(shí)現(xiàn)
    • 1.成員變量
    • 2.構(gòu)造函數(shù)
      • (1)無參構(gòu)造函數(shù)
      • (2)有參構(gòu)造函數(shù)
    • 3.c_str函數(shù)
    • 4.operator[]
    • 5.深淺拷貝問題
      • (1)淺拷貝
      • (2)深拷貝
    • 6.size函數(shù)和capacity函數(shù)
    • 7.reserve函數(shù)
    • 8.resize函數(shù)
    • 9.string的插入函數(shù)
      • (1)push_back函數(shù)
      • (2)append函數(shù)
      • (3)operator+=函數(shù)
      • (4)insert函數(shù)
    • 10.字符串比較函數(shù)
    • 11.迭代器
    • 12.erase函數(shù)
    • 13.find函數(shù)
    • 14.string類的流插入和流提取函數(shù)
    • 15.swap函數(shù)
    • 16.拷貝構(gòu)造函數(shù)和賦值函數(shù)的現(xiàn)代寫法
  • 二、代碼

十多年專注成都網(wǎng)站制作,成都定制網(wǎng)頁設(shè)計(jì),個(gè)人網(wǎng)站制作服務(wù),為大家分享網(wǎng)站制作知識、方案,網(wǎng)站設(shè)計(jì)流程、步驟,成功服務(wù)上千家企業(yè)。為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁設(shè)計(jì)及定制高端網(wǎng)站建設(shè)服務(wù),專注于成都定制網(wǎng)頁設(shè)計(jì),高端網(wǎng)頁制作,對成都廣告推廣等多個(gè)方面,擁有豐富的網(wǎng)站營銷經(jīng)驗(yàn)。一、string類的模擬實(shí)現(xiàn) 1.成員變量

string類的成員變量分別是存儲字符串的一段空間_str,表示字符串的有效字符個(gè)數(shù)_size和表示存儲有效字符空間的_capacity。

private:
    char *_str;
    size_t _size;// 有效字符的個(gè)數(shù)
    size_t _capacity;// 存儲有效字符的空間
2.構(gòu)造函數(shù) (1)無參構(gòu)造函數(shù)

string類的無參構(gòu)造函數(shù)非常簡單,_size和_capacity都設(shè)置為0,但是_str不能設(shè)置為nullptr,因?yàn)楦鶕?jù)標(biāo)準(zhǔn)庫里的string設(shè)計(jì),無參構(gòu)造函數(shù)里的_str設(shè)置為空串。

string()
    :_size(0)
    ,_capacity(0)
{// 按照標(biāo)準(zhǔn)庫里的string設(shè)計(jì)無參構(gòu)造函數(shù)
    // _str存放一個(gè)空串,而不是直接設(shè)置為nullptr
    _str = new char[1];
    _str[0] = '\0';
}
(2)有參構(gòu)造函數(shù)

首先,string類的有參構(gòu)造函數(shù)其實(shí)可以設(shè)計(jì)為全缺省函數(shù),缺省值設(shè)置為空串,當(dāng)沒有傳入?yún)?shù)時(shí)使用缺省值,將_str設(shè)置為空串,這樣就可以不需要定義無參構(gòu)造函數(shù)了。其次,如果傳入了參數(shù),就將_size和_capacity設(shè)置為形參的長度,然后開一段大小和形參相同的空間給_str,最后將值拷貝過去即可。

string(const char *str = "")
    :_size(strlen(str))
    ,_capacity(_size)
{// strcpy函數(shù)會(huì)將\0也拷貝過去
    _str = new char[_capacity + 1];
    strcpy(_str, str);
}
3.c_str函數(shù)

string類的c_str函數(shù)是為了方便string字符串配合C語言的字符串函數(shù)接口使用而設(shè)計(jì)的,它可以返回string對象的char * 類型的指針,這個(gè)函數(shù)實(shí)現(xiàn)起來非常簡單,直接返回我們成員變量_str即可,它就是一個(gè)char * 類型的指針。需要注意的是,c_str函數(shù)的返回類型是 const char*,要加上const的原因調(diào)用該函數(shù)只能獲取指針,并不能對指針進(jìn)行修改。

const char *c_str() const
{return _str;
}
4.operator[]

string類中對運(yùn)算符[]的重載是很重要的,提供這個(gè)運(yùn)算符重載可以方便我們對string對象進(jìn)行下標(biāo)訪問,也可以修改該下標(biāo)對應(yīng)的值。函數(shù)的返回類型是char&,一般引用返回是為了減少拷貝,但這里我們只需要返回一個(gè)字符,拷貝成本并不大。這里使用引用返回的目的是允許修改,因?yàn)橐镁褪欠祷刂档囊粋€(gè)別名,我們就可以對返回值進(jìn)行修改。

char &operator[](size_t pos)
{return _str[pos];
}

// 再提供一個(gè)const版本,讓const對象也能調(diào)用,就不會(huì)出現(xiàn)權(quán)限放大的問題
const char &operator[](size_t pos) const
{return _str[pos];
}
5.深淺拷貝問題 (1)淺拷貝

在C++的類設(shè)計(jì)中,如果我們沒有寫拷貝構(gòu)造函數(shù),那么會(huì)使用默認(rèn)的拷貝構(gòu)造函數(shù),默認(rèn)的拷貝構(gòu)造函數(shù)是淺拷貝,也就是簡單地將一個(gè)對象的值拷貝給另一個(gè)對象。如果對于內(nèi)置類型的話淺拷貝沒什么太大的影響,但如果是自定義類型,就比如我們的string類,將一個(gè)string對象的值拷貝給另一個(gè)string對象本質(zhì)上是將指針內(nèi)容進(jìn)行拷貝,這樣就會(huì)導(dǎo)致兩個(gè)對象指向同一塊空間。

在這里插入圖片描述

這樣淺拷貝的話會(huì)引發(fā)一些問題,比如析構(gòu)函數(shù)的時(shí)候會(huì)被析構(gòu)兩次,或者一個(gè)對象改變自己字符串的值會(huì)影響另一個(gè)對象字符串的值。

(2)深拷貝

深拷貝和淺拷貝不同的是深拷貝是另外開一塊同樣的空間,然后將字符串的內(nèi)容拷貝下來,這樣就讓兩個(gè)對象指向不同的空間,但這兩個(gè)不同空間的字符串值是相同的,這樣就解決了自定義類型淺拷貝帶來的問題。

在這里插入圖片描述

要完成深拷貝的話就需要我們自己寫拷貝構(gòu)造函數(shù)了,不能使用默認(rèn)的拷貝構(gòu)造函數(shù):

string(const string &s)
    :_size(strlen(s._str))
    ,_capacity(_size)
{_str = new char[_capacity + 1];
    strcpy(_str, s._str);
}

賦值運(yùn)算符重載和拷貝構(gòu)造一樣,如果我們沒有寫賦值運(yùn)算符重載,默認(rèn)使用的是淺拷貝,所以我們也要自己寫賦值運(yùn)算符重載。
賦值運(yùn)算符重載的寫法和拷貝構(gòu)造函數(shù)的寫法不同,不能直接復(fù)制過來,因?yàn)橘x值運(yùn)算符重載面對的是兩個(gè)都已經(jīng)存在了的開好空間了的對象,有可能需要被賦值的對象的空間比較小,會(huì)存在越界訪問的問題;也有可能需要被賦值的對象的空間比較大,雖然不會(huì)出現(xiàn)越界訪問但會(huì)造成空間的浪費(fèi)。所以簡單粗暴的就是先釋放原有的空間,再進(jìn)行復(fù)制。

string& operator=(const string& s)
{// 防止出現(xiàn)自己給自己賦值導(dǎo)致的錯(cuò)誤
    if (this != &s)
    {delete[] _str;
        _str = new char[s._capacity + 1];
        strcpy(_str, s._str);
        _size = s._size;
        _capacity = s._capacity;
    }

    return *this;
}
6.size函數(shù)和capacity函數(shù)

這兩個(gè)函數(shù)很簡單,分別返回_size的值和_capacity的值即可。

size_t size() const
{return _size;
}

size_t capacity() const
{return _capacity;
}
7.reserve函數(shù)

reserve函數(shù)是擴(kuò)容函數(shù),當(dāng)容量不足時(shí),會(huì)擴(kuò)大到指定的容量。這個(gè)函數(shù)實(shí)現(xiàn)起來比較簡單,當(dāng)指定容量大于當(dāng)前容量時(shí)說明要擴(kuò)容,我們定義一個(gè)新的空間,把這塊新空間的大小設(shè)置為指定的新容量,然后將原來字符串的值拷貝到新開的空間上,再將原來的空間釋放,讓_str指針指向新的空間,最后更新_capacity的值即可。

void reserve(size_t n)
{// 如果容量不夠,就要擴(kuò)容
    if (n >_capacity)
    {char* tmp = new char[n + 1];// 保留一個(gè)位置給\0
        strcpy(tmp, _str);
        delete[] _str;
        _str = tmp;
        _capacity = n;
    }
}
8.resize函數(shù)

resize函數(shù)也是擴(kuò)容函數(shù),但是它改變的是_size的值,這個(gè)函數(shù)的實(shí)現(xiàn)分三種情況討論(假設(shè)新的size值為newsize):

  1. 當(dāng)newsize >_capacity時(shí):說明容量不夠了,首先要進(jìn)行擴(kuò)容,可以服用reserve函數(shù)進(jìn)行擴(kuò)容操作,并將字符串填充滿。
  2. 當(dāng)_size< newsize<= capacity時(shí):說明容量是夠的,所以只需要增大_size的值,并且將字符串填滿即可。
  3. 當(dāng)newsize<= _size時(shí):只需要縮小_size的值即可。
void resize(size_t n, char ch = '\0')
{// 如果容量不夠,首先要擴(kuò)容
    if (n >_capacity)
    {reserve(n);
    }

    // 到這里代表容量一定足夠
    for (size_t i = _size; i< n; i++)
    {_str[i] = ch;
    }
    _size = n;
    _str[_size] = '\0';
}
9.string的插入函數(shù) (1)push_back函數(shù)

push_back函數(shù)是在字符串末尾插入一個(gè)字符,首先需要考慮容量是否滿了,如果容量滿了就需要先擴(kuò)容。擴(kuò)容的時(shí)候還需要特別關(guān)注一下如果字符串是空串,那么_capacity的值是0,需要特殊處理一下。擴(kuò)容完以后就是簡單的尾插操作即可。

void push_back(char ch)
{// 說明容量滿了,需要先擴(kuò)容
    if (_size == _capacity)
    {// 需要考慮到_capacity是不是等于0這個(gè)情況
        reserve(_capacity == 0 ? 4 : _capacity * 2);
    }
    _str[_size] = ch;
    _size++;
    _str[_size] = '\0';
}
(2)append函數(shù)

我們只實(shí)現(xiàn)append插入一個(gè)常量字符串的函數(shù),首先是要計(jì)算新插入的字符串加上原來的字符串一共有多長,然后要判斷這個(gè)長度是否大于_capacity,如果是的話就需要擴(kuò)容。最后直接用strcpy函數(shù)拼接起來即可。

void append(const char* str)
{// 先計(jì)算插入字符串以后的長度
    int len = _size + strlen(str);
    // 如果容量不大需要擴(kuò)容
    if (len >_capacity)
    {reserve(len);
    }

    strcpy(_str + _size, str);
    _size = len;
    _str[_size] = '\0';
}
(3)operator+=函數(shù)

這個(gè)函數(shù)只需要復(fù)用push_back函數(shù)和append函數(shù)即可。

string& operator+=(const char* str)
{append(str);
    return *this;
}

string& operator+=(char ch)
{push_back(ch);
    return *this;
}
(4)insert函數(shù)

insert函數(shù)我們實(shí)現(xiàn)兩個(gè)版本,一個(gè)是插入一個(gè)字符,一個(gè)是插入一個(gè)常量字符串。這個(gè)函數(shù)實(shí)現(xiàn)的邏輯也比較簡單,就是將pos位置到_size位置的字符往后挪動(dòng),然后在空位處插入新的字符或者字符串。

string& insert(size_t pos, char ch)
{// 斷言防止pos出現(xiàn)非法范圍,當(dāng)pos=_size時(shí)就是push_back
    // 所以push_back可以復(fù)用這個(gè)insert
    assert(pos<= _size);

    if (_size == _capacity)
    {reserve(_capacity == 0 ? 4 : _capacity * 2);
    }
    size_t end = _size + 1;
    while (end >pos)
    {_str[end] = _str[end - 1];
        end--;
    }
    _str[pos] = ch;
    _size++;

    return *this;
}

string& insert(size_t pos, const char* str)
{assert(pos<= _size);

    size_t len = strlen(str);
    if (_size + len >_capacity)
    {reserve(_size + len);
    }

    size_t end = _size + len;
    while (end >pos + len -1)
    {_str[end] = _str[end - len];
        end--;
    }
    strncpy(_str + pos, str, len);
    _size += len;

    return *this;
}
10.字符串比較函數(shù)

字符串比較函數(shù)需要實(shí)現(xiàn)各種比較符號的運(yùn)算符重載函數(shù),字符串比較的原理是根據(jù)字符的ASCII碼值的大小進(jìn)行比較,這可以利用C語言的strcmp函數(shù)進(jìn)行比較。其實(shí)我們只需要實(shí)現(xiàn)其中個(gè)別幾個(gè)函數(shù),剩下的直接復(fù)用即可。

bool operator<(const string& s1, const string& s2)
    {return strcmp(s1.c_str(), s2.c_str())< 0;
    }

    bool operator<=(const string& s1, const string& s2)
    {return strcmp(s1.c_str(), s2.c_str())<= 0;
    }

    bool operator==(const string& s1, const string& s2)
    {return strcmp(s1.c_str(), s2.c_str()) == 0;
    }

    bool operator>(const string& s1, const string& s2)
    {return !(s1<= s2);
    }

    bool operator>=(const string& s1, const string& s2)
    {return !(s1< s2);
    }

    bool operator!=(const string& s1, const string& s2)
    {return !(s1 == s2);
    }
11.迭代器

string類的迭代器非常簡單,其實(shí)就是 char* 類型的指針,與迭代器配合使用的begin函數(shù)和end函數(shù)實(shí)現(xiàn)起來也非常簡單,begin函數(shù)只要返回字符串第一個(gè)字符的地址即可,end函數(shù)只要返回字符串最后一個(gè)字符的下一個(gè)位置的地址。同時(shí),我們也要實(shí)現(xiàn)一個(gè)const的迭代器和const修飾的begin函數(shù)和end函數(shù),讓const對象也可以調(diào)用。

typedef char* iterator;
typedef const char* const_iterator;

iterator begin()
{return _str;
}

iterator end()
{return _str + _size;
}

const_iterator begin() const
{return _str;
}

const_ iterator end() const
{return _str + _size;
}

string的遍歷方式有三種,分別是通過下標(biāo)遍歷、通過迭代器遍歷和通過范圍for來遍歷,通過下標(biāo)遍歷借助operator[]函數(shù)即可,通過迭代器遍歷只要實(shí)現(xiàn)迭代器即可,范圍for遍歷其實(shí)底層也是通過迭代器來遍歷的,例如下面的例子:ch是迭代器解引用的一份拷貝,假設(shè)迭代器變量為it,等價(jià)于ch = *it;

void test_string1()
{JJP::string s("hello");

    for (auto ch : s)
    {cout<< ch;
    }
    cout<< endl;
}

所以我們就能意識到一個(gè)問題,如果我們對ch的值進(jìn)行改變的話,原來的字符串的值并不會(huì)發(fā)生改變,因?yàn)楦淖兊氖莄h這個(gè)變量的值,并沒有改變*it的值,因此,如果想要改變原來字符串的值,需要帶上引用。

void test_string1()
{JJP::string s("hello");

    // 只改變ch的值,不能改變原字符串的值
    for (auto ch : s)
    {ch -= 1;
        cout<< ch;
    }
    cout<< endl;
    cout<< s.c_str()<< endl;

    // 加上引用就可以改變原來字符串的值
    for (auto& ch : s)
    {ch -= 1;
        cout<< ch;
    }
    cout<< endl;
    cout<< s.c_str()<< endl;
}
12.erase函數(shù)

string的刪除函數(shù)與插入函數(shù)相反,挪動(dòng)數(shù)據(jù)覆蓋即可。

string& erase(size_t pos, size_t len = npos)
{assert(pos<= _size);

    if (len == npos || pos + len >= _size)
    {_str[pos] = '\0';
        _size = pos;
    }
    else
    {size_t begin = pos + len;
        while (begin<= _size)
        {_str[begin - len] = _str[begin];
            begin++;
        }
        _size -= len;
    }
}
13.find函數(shù)

find函數(shù)實(shí)現(xiàn)起來也非常簡單,只需要遍歷查找即可。我們實(shí)現(xiàn)一個(gè)查找字符函數(shù)和一個(gè)查找字符串函數(shù),查找字符函數(shù)挨著遍歷去查找即可,查找字符串函數(shù)可以使用C語言的庫函數(shù)strstr去查找子串。

size_t find(char ch, size_t pos = 0)
{for (; pos< _size; pos++)
    {if (_str[pos] == ch)
        {return pos;
        }
    }

    return npos;
}

size_t find(const char* str, size_t pos = 0)
{const char* p = strstr(_str + pos, str);
    if (p == nullptr)
    {return npos;
    }
    else
    {return p-_str;
    }
}
14.string類的流插入和流提取函數(shù)

我們還需要實(shí)現(xiàn)以下流插入和流提取函數(shù),這樣方便我們輸入字符串和輸出字符串。

ostream& operator<<(ostream& out, const string& s)
	{for (auto ch : s)
		{	out<< ch;
		}

		return out;
	}

    istream& operator>>(istream& in, string& s)
	{// 先將字符串清空
        s.resize(0, '\0');
        // 這種方法可能存在多次擴(kuò)容的情況,效率較低
		//char ch;
		in >>ch;
		//ch = in.get();
		//while (ch != ' ' && ch != '\n')
		//{//	s += ch;
		//	//in >>ch;
		//	ch = in.get();
		//}

		//return in;

		char ch;
		ch = in.get();
		char buff[128] = {'\0'};
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{	buff[i++] = ch;
			if (i == 127)
			{		s += buff;
				memset(buff, '\0', 128);
				i = 0;
			}

			ch = in.get();
		}

		s += buff;
		return in;
	}
15.swap函數(shù)

string類的swap函數(shù)是在底層直接交換兩個(gè)對象的指針,所以實(shí)現(xiàn)起來非常簡單。

void swap(string& s)
{std::swap(_str, s._str);
    std::swap(_size, s._size);
    std::swap(_capacity, s._capacity);
}
16.拷貝構(gòu)造函數(shù)和賦值函數(shù)的現(xiàn)代寫法

我們上面寫的拷貝構(gòu)造函數(shù)方法太麻煩了,有一種更加方便的寫法,就是定義一個(gè)局部對象tmp,讓tmp去調(diào)用常量字符串構(gòu)造函數(shù)從而完成深拷貝,最后將tmp與this交換即可。需要注意的是一開始的時(shí)候this的_str、_size和_capacity需要初始化一下,因?yàn)槿绻麤]有初始化最后交換給tmp的就是隨機(jī)值,tmp在最后析構(gòu)的時(shí)候可能會(huì)報(bào)錯(cuò)。

// 現(xiàn)代寫法,讓tmp去完成深拷貝,復(fù)用常量字符串構(gòu)造函數(shù)
string(const string &s)
    :_str(nullptr)
    ,_size(0)
    ,_capacity(0)
{string tmp(s._str);
    swap(tmp);// 這個(gè)調(diào)用的是string類的swap函數(shù)
}

除了拷貝構(gòu)造函數(shù)有現(xiàn)代寫法,賦值運(yùn)算符重載函數(shù)也有現(xiàn)代寫法。第一種現(xiàn)代寫法和拷貝構(gòu)造函數(shù)的寫法相似,也是借助局部對象tmp完成深拷貝,最后交換即可。

string& operator=(const string& s)
{if (this != &s)
    {string tmp(s._str);
        swap(tmp);
    }

    return *this;
}

第二種寫法更加的簡潔粗暴,我們可以直接將形參的對象與this交換即可。由于我們參數(shù)傳遞是傳值傳參,不是引用傳參,而是實(shí)參的一份臨時(shí)拷貝,所以交換以后并不會(huì)影響實(shí)參的值。

// 現(xiàn)代寫法更簡潔的版本
string& operator=(string s)
{swap(s);
    return *this;
}
二、代碼
#pragma once
#include#include#include 

// 使用命名空間為了不讓庫的string和我們自己定義的string沖突
namespace JJP
{class string
    {public:
        typedef char* iterator;
        typedef const char* const_iterator;

        iterator begin()
        {return _str;
        }

        iterator end()
        {return _str + _size;
        }

        const_iterator begin() const
        {return _str;
        }

        const_iterator end() const
        {return _str + _size;
        }

        // 可以不給無參構(gòu)造函數(shù),直接將有參構(gòu)造函數(shù)設(shè)計(jì)成全缺省
        // 可以達(dá)到一樣的效果
        // string()
        //     :_size(0)
        //     ,_capacity(0)
        // {//     // 按照標(biāo)準(zhǔn)庫里的string設(shè)計(jì)無參構(gòu)造函數(shù)
        //     // _str存放一個(gè)空串,而不是直接設(shè)置為nullptr
        //     _str = new char[1];
        //     _str[0] = '\0';
        // }
        string(const char *str = "")
            :_size(strlen(str))
            ,_capacity(_size)
        {// strcpy函數(shù)會(huì)將\0也拷貝過去
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }

        ~string()
        {if (_str)
            {delete[] _str;
                _str = nullptr;
                _size = _capacity = 0;
            }
        }

        const char *c_str() const
        {return _str;
        }

        char &operator[](size_t pos)
        {return _str[pos];
        }

        const char &operator[](size_t pos) const
        {return _str[pos];
        }

        // // 原始寫法,代碼比較多
        // string(const string &s)
        //     :_size(strlen(s._str))
        //     ,_capacity(_size)
        // {//     _str = new char[_capacity + 1];
        //     strcpy(_str, s._str);
        // }

        void swap(string& s)
		{	std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

        // 現(xiàn)代寫法,讓tmp去完成深拷貝,復(fù)用常量字符串構(gòu)造函數(shù)
        string(const string &s)
            :_str(nullptr)
            ,_size(0)
            ,_capacity(0)
        {string tmp(s._str);
            swap(tmp);// 這個(gè)調(diào)用的是string類的swap函數(shù)
        }

        // 原始寫法
        // string &operator=(const string &s)
        // {//     // 防止出現(xiàn)自己給自己賦值導(dǎo)致的錯(cuò)誤
        //     if (this != &s)
        //     {//         delete[] _str;
        //         _str = new char[s._capacity + 1];
        //         strcpy(_str, s._str);
        //         _size = s._size;
        //         _capacity = s._capacity;
        //     }

        //     return *this;
        // }

        // 現(xiàn)代寫法
        // string& operator=(const string& s)
		// {// 	if (this != &s)
		// 	{// 		string tmp(s._str);
		// 		swap(tmp);
		// 	}

		// 	return *this;
		// }

        // 現(xiàn)代寫法更簡潔的版本
        string& operator=(string s)
		{	swap(s);
			return *this;
		}

        size_t size() const
        {return _size;
        }

        size_t capacity() const
        {return _capacity;
        }

        void push_back(char ch)
        {// 說明容量滿了,需要先擴(kuò)容
            if (_size == _capacity)
            {// 需要考慮到_capacity是不是等于0這個(gè)情況
                reserve(_capacity == 0 ? 4 : _capacity * 2);
            }
            _str[_size] = ch;
            _size++;
            _str[_size] = '\0';
        }

        void append(const char* str)
        {// 先計(jì)算插入字符串以后的長度
            int len = _size + strlen(str);
            // 如果容量不大需要擴(kuò)容
            if (len >_capacity)
            {reserve(len);
            }

            strcpy(_str + _size, str);
            _size = len;
            _str[_size] = '\0';
        }

        void reserve(size_t n)
        {// 如果容量不夠,就要擴(kuò)容
            if (n >_capacity)
            {char* tmp = new char[n + 1];// 保留一個(gè)位置給\0
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;
                _capacity = n;
            }
        }

        string& operator+=(const char* str)
        {append(str);
            return *this;
        }

        string& operator+=(char ch)
        {push_back(ch);
            return *this;
        }

        void resize(size_t n, char ch = '\0')
        {// 如果容量不夠,首先要擴(kuò)容
            if (n >_capacity)
            {reserve(n);
            }

            // 到這里代表容量一定足夠
            for (size_t i = _size; i< n; i++)
            {_str[i] = ch;
            }
            _size = n;
            _str[_size] = '\0';
        }

        string& insert(size_t pos, char ch)
        {// 斷言防止pos出現(xiàn)非法范圍,當(dāng)pos=_size時(shí)就是push_back
            // 所以push_back可以復(fù)用這個(gè)insert
            assert(pos<= _size);

            if (_size == _capacity)
            {reserve(_capacity == 0 ? 4 : _capacity * 2);
            }
            size_t end = _size + 1;
            while (end >pos)
            {_str[end] = _str[end - 1];
                end--;
            }
            _str[pos] = ch;
            _size++;

            return *this;
        }

        string& insert(size_t pos, const char* str)
        {assert(pos<= _size);

            size_t len = strlen(str);
            if (_size + len >_capacity)
            {reserve(_size + len);
            }

            size_t end = _size + len;
            while (end >pos + len -1)
            {_str[end] = _str[end - len];
                end--;
            }
            strncpy(_str + pos, str, len);
            _size += len;

            return *this;
        }

        string& erase(size_t pos, size_t len = npos)
        {assert(pos<= _size);

            if (len == npos || pos + len >= _size)
            {_str[pos] = '\0';
                _size = pos;
            }
            else
            {size_t begin = pos + len;
                while (begin<= _size)
                {_str[begin - len] = _str[begin];
                    begin++;
                }
                _size -= len;
            }

            return *this;
        }

        size_t find(char ch, size_t pos = 0)
        {for (; pos< _size; pos++)
            {if (_str[pos] == ch)
                {return pos;
                }
            }

            return npos;
        }

        size_t find(const char* str, size_t pos = 0)
        {const char* p = strstr(_str + pos, str);
            if (p == nullptr)
            {return npos;
            }
            else
            {return p-_str;
            }
        }

    private:
        char *_str;
        size_t _size;// 有效字符的個(gè)數(shù)
        size_t _capacity;// 存儲有效字符的空間

        const static size_t npos;
    };

    const size_t string::npos = -1;

    std::ostream& operator<<(std::ostream& out, const string& s)
	{for (auto ch : s)
		{	out<< ch;
		}

		return out;
	}

    std::istream& operator>>(std::istream& in, string& s)
	{// 先將字符串清空
        s.resize(0, '\0');
        // 這種方法可能存在多次擴(kuò)容的情況,效率較低
		//char ch;
		in >>ch;
		//ch = in.get();
		//while (ch != ' ' && ch != '\n')
		//{//	s += ch;
		//	//in >>ch;
		//	ch = in.get();
		//}

		//return in;

		char ch;
		ch = in.get();
		char buff[128] = {'\0'};
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{	buff[i++] = ch;
			if (i == 127)
			{		s += buff;
				memset(buff, '\0', 128);
				i = 0;
			}

			ch = in.get();
		}

		s += buff;
		return in;
	}

    bool operator<(const string& s1, const string& s2)
    {return strcmp(s1.c_str(), s2.c_str())< 0;
    }

    bool operator<=(const string& s1, const string& s2)
    {return strcmp(s1.c_str(), s2.c_str())<= 0;
    }

    bool operator==(const string& s1, const string& s2)
    {return strcmp(s1.c_str(), s2.c_str()) == 0;
    }

    bool operator>(const string& s1, const string& s2)
    {return !(s1<= s2);
    }

    bool operator>=(const string& s1, const string& s2)
    {return !(s1< s2);
    }

    bool operator!=(const string& s1, const string& s2)
    {return !(s1 == s2);
    }
}

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

網(wǎng)頁標(biāo)題:C++關(guān)于string類的模擬實(shí)現(xiàn)-創(chuàng)新互聯(lián)
URL標(biāo)題:http://muchs.cn/article44/dgicee.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)網(wǎng)站建設(shè)外貿(mào)建站、電子商務(wù)網(wǎng)站制作、面包屑導(dǎo)航、App開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站制作