C++字符串類的封裝你真的了解嗎
字符串類的封裝
常規(guī)代碼
頭文件
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class MyString//字符串應(yīng)該是維護(hù)著一個(gè)字符數(shù)組的,在堆區(qū) { public: MyString(const char* str);//有參構(gòu)造函數(shù) MyString(const MyString& str);//拷貝構(gòu)造函數(shù) ~MyString();//析構(gòu)函數(shù)(是需要的,因?yàn)檫@個(gè)類中還維護(hù)著一個(gè)指針,需要自己釋放) private: char* pString;//維護(hù)在堆區(qū)開(kāi)辟的字符數(shù)組 int m_Size;//字符串長(zhǎng)度(不統(tǒng)計(jì)\0) };
在頭文件中定義了MyString類中應(yīng)該有的屬性和三個(gè)函數(shù)。(有參構(gòu)造函數(shù)接收字符串并創(chuàng)建對(duì)象)(拷貝構(gòu)造函數(shù)可以接收同類型的對(duì)象并且復(fù)制出一個(gè)新的對(duì)象)(析構(gòu)函數(shù)負(fù)責(zé)在釋放掉本對(duì)象的同時(shí)釋放掉對(duì)象中維護(hù)的指針)
函數(shù)實(shí)現(xiàn)文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"myString.h"; //MyString str = "123"; MyString::MyString(const char* str)//有參構(gòu)造函數(shù),傳進(jìn)去的參數(shù)是一個(gè)字符串,返回的是MyString類型的對(duì)象。 { cout<<"MyString的有參構(gòu)造函數(shù)調(diào)用"<<endl; this->pString = new char[strlen(str) + 1];//給本對(duì)象的pString準(zhǔn)備空間。 strcpy(this->pString, str);//將傳進(jìn)來(lái)帶的字符串的地址也傳給本對(duì)象的pString處,str是字符串,不能調(diào)用pString屬性。 this->m_Size = strlen(str); } MyString::MyString(const MyString& str)//拷貝構(gòu)造函數(shù) { //這個(gè)需要深拷貝,因?yàn)轭愔杏袀€(gè)指針。注意:深拷貝是對(duì)指針進(jìn)行的深拷貝,也就是會(huì)傳進(jìn)來(lái)個(gè)對(duì)象,然后給這個(gè)對(duì)象中的指針 分配傳進(jìn)來(lái)的對(duì)象中的指針的大小的空間,然后將這個(gè)值也賦值到本指針中。 cout << "MyString的拷貝函數(shù)調(diào)用" << endl; this->pString = new char[strlen(str.pString)+1]; strcpy(this->pString , str.pString); this->m_Size = str.m_Size; } MyString::~MyString()//析構(gòu)(是需要的,因?yàn)檫@個(gè)類中還維護(hù)著一個(gè)指針,需要自己釋放) { cout << "MyString的析構(gòu)函數(shù)調(diào)用" << endl; if (this->pString != NULL) { delete[] this->pString; this->pString = NULL; } }
拷貝構(gòu)造和有參構(gòu)造的區(qū)別就是:
1,有參構(gòu)造傳進(jìn)去的是一個(gè)字符串,返回成一個(gè)對(duì)象。所以要的是對(duì)象的各個(gè)屬性與字符串的屬性的匹配。
2,拷貝構(gòu)造傳進(jìn)去的是一個(gè)對(duì)象,返回的也是一個(gè)對(duì)象,所以要的是傳進(jìn)來(lái)的對(duì)象和本對(duì)象(要?jiǎng)?chuàng)建的對(duì)象)之間屬性的對(duì)應(yīng)。
3,如果拷貝構(gòu)造的時(shí)候發(fā)現(xiàn)需要拷貝個(gè)指針,那么就不能直接使用編譯器的拷貝構(gòu)造函數(shù)了,因?yàn)榫幾g器的拷貝構(gòu)造函數(shù)構(gòu)造出來(lái)的對(duì)象的指針是和傳進(jìn)來(lái)的對(duì)象的指針是指向同一塊地方的,那么等到需要釋放指針的時(shí)候就會(huì)出現(xiàn)重釋放的錯(cuò)誤。**(這也是為什么需要自己重新創(chuàng)建拷貝構(gòu)造的原因)**如果類中不需要維護(hù)指針,那么就不需要自己寫(xiě)拷貝構(gòu)造(自己為指針再創(chuàng)建空間)。
Test文件
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; #include "myString.h"; int main() { MyString str = "abc";//調(diào)用默認(rèn)構(gòu)造 //和后面的一樣MyString str("abc"); MyString str2 = str;//調(diào)用拷貝構(gòu)造 return 0; }
注意,這里的“abc”就是傳進(jìn)來(lái)的字符串str,然后這里的str就是創(chuàng)建出來(lái)的MyString類型的對(duì)象。
運(yùn)行的結(jié)果:
MyString的有參構(gòu)造函數(shù)調(diào)用
MyString的拷貝函數(shù)調(diào)用
MyString的析構(gòu)函數(shù)調(diào)用
MyString的析構(gòu)函數(shù)調(diào)用
重載左移>>
如果想進(jìn)行
cout<<str<<endl;
代碼肯定會(huì)報(bào)錯(cuò),因?yàn)閟tr是MyString類型的對(duì)象,<<不認(rèn)識(shí)這個(gè)。
所以,這個(gè)時(shí)候就需要重載一下<<左移運(yùn)算符,可以在函數(shù)文件中實(shí)現(xiàn)。(需要用全局函數(shù)配合友元進(jìn)行重載)
實(shí)現(xiàn)函數(shù):
ostream& operator<<(ostream& cout, MyString& str) //重載左移運(yùn)算符 { cout << str.pString;//這里的pString是類中的私有屬性,所以需要在原類(在頭文件中)中給整個(gè)重載函數(shù)設(shè)置友元 return cout; }
頭文件:
class MyString { friend ostream& operator<<(ostream& cout, MyString& str);//設(shè)置的友元 public: private: };
這樣cout << str << endl;
這行代碼就可以調(diào)用了。
重載右移<<
如果想進(jìn)行
cin>>str;
代碼肯定也會(huì)報(bào)錯(cuò),因?yàn)閟tr是MyString類型的對(duì)象,>>不認(rèn)識(shí)這個(gè)。
所以,這個(gè)時(shí)候就要重載一下>>右移運(yùn)算符,可以在函數(shù)文件中實(shí)現(xiàn)。(需要用全局函數(shù)配合友元進(jìn)行重載)
實(shí)現(xiàn)函數(shù):
istream& operator>>(istream& cin, MyString& str)//重載右移運(yùn)算符 { //應(yīng)該先清空原來(lái)的堆區(qū)數(shù)據(jù) if (str.pString)//這里的pString是對(duì)象中的私有屬性,所以需要在原類中加上這個(gè)重載函數(shù)的友元聲明 { delete[] str.pString; str.pString = NULL; } //不用急著直接將輸入的內(nèi)容傳給pString,可以先開(kāi)辟臨時(shí)數(shù)組,記錄著輸入內(nèi)容。 char buf[1024]; cin >> buf; //因?yàn)槭亲约褐剌d的函數(shù),剛才將str的pString刪除了,現(xiàn)在需要重新申請(qǐng)空間。 str.pString = new char[strlen(buf) + 1]; strcpy(str.pString, buf); str.m_Size = strlen(buf);//別忘了還要把大小考進(jìn)str的size中,因?yàn)閭鬟M(jìn)來(lái)一串字符以后,對(duì)象中的長(zhǎng)度還保持著原先的長(zhǎng)度,所以需要進(jìn)行修改。 cout << str.m_Size << endl; return cin; }
頭文件:
class MyString//字符串應(yīng)該是維護(hù)著一個(gè)字符數(shù)組的,在堆區(qū) { friend istream& operator>>(istream& cin, MyString& str); public: private: };
然后就能給str的pString賦值了。
重載右移運(yùn)算符的時(shí)候的清空原來(lái)字符串中的內(nèi)容好像不太重要,刪除了也能正常運(yùn)行。創(chuàng)建臨時(shí)數(shù)組記錄(數(shù)組大小夠大即可),然后將賦值,最后別忘了更改對(duì)象中的size。
重載賦值=
如果想進(jìn)行:
str2 = str1
直接將兩個(gè)對(duì)象進(jìn)行=運(yùn)行起來(lái)代碼肯定會(huì)崩,因?yàn)椋喝截惲?,刪除對(duì)象的時(shí)候會(huì)出現(xiàn)淺拷貝的問(wèn)題。
如果想進(jìn)行:
str2 = “abc"
直接將字符串賦值給字符串肯定也是不行的。
所以需要重載兩個(gè)不同參數(shù)的 = 運(yùn)算符。(一種參數(shù)是對(duì)象,一種參數(shù)是字符串)
MyString& operator=(const MyString& str); MyString& operator=(const char* str);
返回值必須要是MyString& ,因?yàn)槭褂猛?運(yùn)算符要返回的是自身(str2). 注意在頭函數(shù)中聲明完了以后到實(shí)現(xiàn)文件中去實(shí)現(xiàn)的時(shí)候要寫(xiě)范圍MyString::,而且這個(gè)類的范圍需要寫(xiě)在返回值類型的后面,函數(shù)名的前面。
重載=運(yùn)算符,與重載左移和右移運(yùn)算符不同,不用再像<<和>>一樣使用全局函數(shù)重載了,需要使用成員函數(shù)
頭文件:
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class MyString { friend ostream& operator<<(ostream& cout, MyString& str); friend istream& operator>>(istream& cin, MyString& str); public: MyString(const char* str);//有參構(gòu)造函數(shù) MyString(const MyString& str);//拷貝構(gòu)造函數(shù) ~MyString();//析構(gòu)(是需要的,因?yàn)檫@個(gè)類中還維護(hù)著一個(gè)指針,需要自己釋放) //重載兩個(gè)=運(yùn)算符 MyString& operator=(const MyString& str); MyString& operator=(const char* str); private: char* pString;//維護(hù)在堆區(qū)開(kāi)辟的字符數(shù)組 int m_Size;//字符串長(zhǎng)度(不統(tǒng)計(jì)\0) };
實(shí)現(xiàn)文件:
#define _CRT_SECURE_NO_WARNINGS 1 #include"myString.h"; MyString & MyString::operator=(const MyString & str) { //先判斷原堆區(qū)有沒(méi)有內(nèi)容,如果有先釋放。 if (this->pString) { delete[]this->pString; this->pString = NULL; } //進(jìn)行深拷貝 this->pString = new char[strlen(str.pString) + 1]; strcpy(this->pString, str.pString); this->m_Size = strlen(str.pString); return *this; } MyString & MyString::operator=(const char* str) { //先判斷原堆區(qū)有沒(méi)有內(nèi)容,如果有先釋放。 if (this->pString) { delete[]this->pString; this->pString = NULL; } //進(jìn)行深拷貝 this->pString = new char[strlen(str) + 1]; strcpy(this->pString, str); this->m_Size = strlen(str); return *this; }
Test文件:
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; #include "myString.h"; int main() { MyString str = "abc";//調(diào)用默認(rèn)構(gòu)造 MyString str2 = "bcd"; str = str2; MyString str3 = "abc"; cout << str << endl;//bcd cout << str3 << endl;//abc return 0; }
重載中括號(hào)[ ]
如果項(xiàng)進(jìn)行
str2[0] = 'a';
是不可以的,因?yàn)閇 ]不認(rèn)識(shí)str。
所以需要重載中括號(hào)[]。直接使用成員函數(shù)進(jìn)行重載。
//在頭文件中: char operator[](int index); //在實(shí)現(xiàn)函數(shù)中: char MyString::operator[](int index)//重載中括號(hào) { return this->pString[index]; }
正常來(lái)說(shuō)就返回char類型的數(shù)值就行了,這樣就可讀了。
但是如果想將str2p[1]作為運(yùn)算左值來(lái)修改,那么就需要返回本體char&
//在頭文件中: char& operator[](int index); //在實(shí)現(xiàn)函數(shù)中: char& MyString::operator[](int index)//重載中括號(hào) { return this->pString[index]; } //在Test文件中 int main() { MyString str2 = "bcd"; cout << str2[1] << endl;//c str2[1] = 'z'; cout << str2[1] << endl;//z return 0; }
重載加號(hào)+
如果想實(shí)現(xiàn):
MyString str3 = "abc"; MyString str4 = "def"; MyString str5 = str3 + str4; MyString str6 = str5+"abc";
這樣肯定會(huì)報(bào)錯(cuò),因?yàn)?不認(rèn)識(shí)對(duì)象,也不認(rèn)識(shí)這樣的字符串
所以,需要對(duì)+進(jìn)行重載,使用的還是成員函數(shù),只有一個(gè)參數(shù)。
從題意得,傳進(jìn)去一個(gè)對(duì)象,然后返回出一個(gè)對(duì)象,或者是傳進(jìn)去一個(gè)字符串,返回出一個(gè)對(duì)象。(前提是將第一個(gè)傳進(jìn)去的看作是調(diào)用對(duì)象)
頭文件:
MyString operator+(const MyString& str); MyString operator+(const char* str);
實(shí)現(xiàn)文件:
//重載+運(yùn)算符 MyString MyString:: operator+(const MyString& str) { //本身abc,傳入的是def,剛開(kāi)始應(yīng)該先計(jì)算一下需要開(kāi)辟的內(nèi)存空間。 int newSize = this->m_Size + strlen(str.pString) + 1; char* temp = new char[newSize];//然后將這塊空間開(kāi)辟出來(lái),temp指針指向它。 memset(temp, 0, newSize);//將空間里面的內(nèi)容全部清空。 strcat(temp, this->pString);//將this->pString扔進(jìn)了temp中。 strcat(temp, str.pString);//然后再將str字符串扔進(jìn)去,這樣它們就自己結(jié)合了。 //但是創(chuàng)建好的新的字符串不能直接返回,因?yàn)樾枰祷匾粋€(gè)對(duì)象 //所以就創(chuàng)建一個(gè)新的對(duì)象,然后通過(guò)構(gòu)造函數(shù)將字符串賦給新對(duì)象,最后再返回新對(duì)象。 MyString newString = temp; //還有一點(diǎn),創(chuàng)建的類是空間temp用完了需要釋放 delete[]temp; return newString; } MyString MyString:: operator+(const char* str) { //本身abc,傳入的是def,剛開(kāi)始應(yīng)該先計(jì)算一下需要開(kāi)辟的內(nèi)存空間。 int newSize = this->m_Size + strlen(str) + 1; char* temp = new char[newSize];//然后將這塊空間開(kāi)辟出來(lái),temp指針指向它。 memset(temp, 0, newSize);//將空間里面的內(nèi)容全部清空。 strcat(temp, this->pString);//將this->pString扔進(jìn)了temp中。 strcat(temp, str);//然后再將str字符串扔進(jìn)去,這樣它們就自己結(jié)合了。 //但是創(chuàng)建好的新的字符串不能直接返回,因?yàn)樾枰祷匾粋€(gè)對(duì)象 //所以就創(chuàng)建一個(gè)新的對(duì)象,然后通過(guò)構(gòu)造函數(shù)將字符串賦給新對(duì)象,最后再返回新對(duì)象。 MyString newString = temp; //還有一點(diǎn),創(chuàng)建的類是空間temp用完了需要釋放 delete[]temp; return newString; }
兩種+重載函數(shù)幾乎一樣
TEST文件
int main() { MyString str3 = "abc"; MyString str4 = "def"; MyString str5 = str3 + str4; MyString str6 = str5 + "abc"; cout << str5 << endl;//abcdef cout << str6 << endl;//abcdefabc return 0; }
重載==
ps補(bǔ)充:strcmp函數(shù)中,如果兩個(gè)字符串相等,那么就返回0,如果不相等,那么就返回1。
也是提供兩種重載函數(shù):
//頭文件: //重載==運(yùn)算符 bool operator==(const MyString& str); bool operator==(const char* str); //實(shí)現(xiàn)文件: //重載==運(yùn)算符 bool MyString::operator==(const MyString & str) { if (strcmp(this->pString, str.pString) == 0) return true; else return false; } bool MyString::operator==(const char* str) { if (strcmp(this->pString, str) == 0) return true; else return false; } //Test文件 int main() { MyString str3 = "abc"; MyString str4 = "def"; MyString str5 = str3 + str4; cout << str5 << endl;//abcdef if (str5 == str5) { cout << "是相等的" << endl; } else { cout << "是不相等的" << endl; } //結(jié)果是相等的。 return 0; }
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Opencv二幀差法檢測(cè)運(yùn)動(dòng)目標(biāo)與提取輪廓
這篇文章主要為大家詳細(xì)介紹了Opencv使用二幀差法檢測(cè)運(yùn)動(dòng)目標(biāo)與提取輪廓,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03ros項(xiàng)目調(diào)試:vscode下配置開(kāi)發(fā)ROS項(xiàng)目的詳細(xì)教程
這篇文章主要介紹了ros項(xiàng)目調(diào)試:vscode下配置開(kāi)發(fā)ROS項(xiàng)目,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08C語(yǔ)言經(jīng)典算法例題求100-999之間的“水仙花數(shù)”
本文的主要內(nèi)容,設(shè)計(jì)一個(gè)程序,找出100-999之間的“水仙花數(shù)”,需要的朋友可以參考下2015-07-07C++實(shí)現(xiàn)旋轉(zhuǎn)掃描儀的示例代碼
旋轉(zhuǎn)掃描儀(Rotating?Scanner),也稱為旋轉(zhuǎn)掃描儀或圓形掃描儀,是一種用于獲取圖像和文檔的設(shè)備,下面就跟隨小編一起來(lái)學(xué)習(xí)一下如何使用C++實(shí)現(xiàn)旋轉(zhuǎn)掃描儀功能吧2024-02-02C語(yǔ)言變長(zhǎng)數(shù)組 struct中char data[0]的用法詳解
下面小編就為大家?guī)?lái)一篇C語(yǔ)言變長(zhǎng)數(shù)組 struct中char data[0]的用法詳解。小編覺(jué)得挺不錯(cuò)的現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01