1 簡介 Spring Data Redis是 Spring Data 系列的一部分,它提供了Spring應用程式對Redis的輕鬆配置和使用。它不僅提供了對Redis操作的高級抽象,還支持Jedis和Lettuce兩種連接方式。 可通過簡單的配置就能連接Redis,並且可以切換Jedis和Lett ...
一. 環境
Linux x86_64,g++ 8.5.0
二. 實現
自實現 string 之前一直想寫來著,一直拖著,現在把它完稿。這個版本是比較簡單的版本,有一些可能有不同的或者更好的實現方式,後面有機會會加到裡面。
打算實現的介面如下
class MyString
{
friend std::ostream & operator<<(std::ostream & co, const MyString &ms);
friend std::istream & operator>>(std::istream & ci, MyString &ms);
public:
MyString(const char * s = nullptr);
~MyString();
MyString(const MyString & another);
MyString & operator=(const MyString & another);
MyString operator+(const MyString & another);
MyString & operator+=(const MyString & another);
bool operator>(const MyString & another);
bool operator<(const MyString & another);
bool operator==(const MyString & another);
char & operator[](int n);
char & at(int n);
private:
char * m_str;
};
- 構造函數,參數使用預設參數,預設參數作標記位。不論是否傳遞實參,申請資源時均以數組形式申請。不傳遞實參時,申請一個 char 的數組,有傳遞實參時,以實際的為準。這樣,在釋放資源時,均可以
delete []m_str
形式釋放。
MyString::MyString(const char *str)
{
if (nullptr == str)
{
m_str = new char[1];
*m_str = '\0';
}
else
{
m_str = new char[strlen(str)+1];
strcpy(m_str, str);
}
}
- 拷貝賦值,使用了兩種方式。
第一種是基礎的寫法,先 delete 堆上的空間,再申請新的空間,然後複製內容。需要註意的是,需判斷是否是自賦值的情況。
第二種採用了 copy && swap 技術,相對完善一點,前一種方式,在 delete []m_str
後如果程式出現異常,此時其它地方有使用到 m_str
的話就尷尬了,而後一種方式就沒有這個問題。
// version1
/*
MyString & MyString::operator=(const MyString &another)
{
if (this == &another)
{
return *this;
}
delete []m_str;
int len = strlen(another.m_str);
m_str = new char[len+1];
strcpy(m_str, another.m_str);
return *this;
}
*/
// version2,採用 copy and swap 技術
MyString & MyString::operator=(const MyString &another)
{
if (this == &another)
{
return *this;
}
MyString ms(another);
std::swap(this->m_str, ms.m_str);
return *this;
}
- 重載
+
運算符,成員函數返回一個臨時對象。在申請新的空間後,在使用strcat()
之前需要初始化,否則可能會出現問題。strcat()
是從末尾為 '\0' 的地方開始拼接的。
MyString MyString::operator+(const MyString &another)
{
MyString ms;
int len = strlen(this->m_str) + strlen(another.m_str);
delete []ms.m_str;
ms.m_str = new char[len +1]{0}; // 註意初始化
strcat(strcat(ms.m_str, this->m_str), another.m_str);
return ms;
}
- 重載
+=
運算符,返回值類型是引用類型,這樣可以連續使用+=
。
使用 realloc()
後,在使用 strcat()
連接兩個字元串之前,需要將 m_str
後面一部分新擴充的空間進行初始化。
MyString & MyString::operator+=(const MyString &another)
{
int lenOfSource = strlen(this->m_str);
int lenOfAnother = strlen(another.m_str);
this->m_str = (char *)realloc(this->m_str, lenOfSource+lenOfAnother+1);
memset(this->m_str+lenOfSource, 0, lenOfAnother+1);
strcat(this->m_str, another.m_str);
return *this;
}
- 重載
>
運算符
bool MyString::operator>(const MyString &another)
{
return strcmp(this->m_str, another.m_str) > 0;
}
重載 <
和 ==
與上面類似,就不重覆列舉了。
- 重載 [] 運算符,這個沒啥好說的了。
char & MyString::operator[](int n)
{
return m_str[n];
}
- 成員函數 at()
char & MyString::at(int n)
{
return m_str[n];
}
- 重載輸出 << 和 輸入 >> 運算符。
在測試成員函數前,可以早點寫這兩個函數,測試時就方便列印了,不然還需要單獨添加一個成員函數返回 m_str
了。
重載運算符,目標形式是:
Mystring ms;
cout << ms;
cin >> ms;
對於重載,一般會考慮到成員函數重載和全局重載,但是 ostream
類和 istream
類都是系統提供的類,我們不可能在 ostream
類和 istream
類中進行修改,因此只能放棄成員函數重載。此時,只能是全局重載,即全局函數重載了。
考慮到會連續輸出(cout << a << b;
),因此返回類型是 ostream &
類型,它是經入參而來,入參類型也是 ostream &
。
std::ostream & operator<<(std::ostream & co, const MyString &ms)
{
co << ms.m_str;
return co;
}
輸入運算符與輸出運算符類似,第二個入參不能是 const
類型,因為需要修改入參 ms
。這裡處理的相對簡單了,棧上申請了1024位元組的字元數組用以存儲輸入的數據,實際上會有不夠用的情況。
std::istream & operator>>(std::istream & ci, MyString &ms)
{
// 簡單處理,申請一塊固定大小的記憶體
char ch[1024];
ci >> ch;
delete []ms.m_str;
ms.m_str = new char[strlen(ch)+1];
strcpy(ms.m_str, ch);
return ci;
}
三. 完整代碼,可點擊鏈接 mystring ,如有有問題或不到之處,請指出並交流,看到後我會修改。
四. 參考
C++基礎與提高 王桂林