C++實(shí)現(xiàn)MyString的示例代碼
MyString的構(gòu)造、析構(gòu)、拷貝構(gòu)造、賦值運(yùn)算
class String { char* str; public: String(const char* p = NULL) :str(NULL) { if (p != NULL) { str = new char[strlen(p) + 1];//strlen()計(jì)算至'\0'截至的字符數(shù) strcpy(str, p); } else { str = new char[1]; //額外提供一個(gè)空間 *str = '\0'; } } ~String() { if (str != NULL) { delete[] str; } str = NULL; } //ostream& operator<<(const String* const this, ostream &out) ostream& operator<<(ostream& out)const //重載插入操作符 { if (str != NULL) { out << str; } return out; } String(const String& s):str(NULL) { //str = s.str; 淺拷貝 是同一個(gè)空間,會(huì)造成一個(gè)空間釋放兩次 //深拷貝 str = new char[strlen(s.str)+1]; strcpy(str, s.str); } String& operator=(const String& s) { if(this != &s) { delete[]str; str = new char[strlen(s.str)+1] strcpy(str,s.str); } return *this; } }; ostream& operator<<(ostream& out, const String& s) { s << out; //s.operator<<(cout); //operator<<(&s1,cout); return out; } int main() { String s1("123"); s1 << cout; //s1.operator<<(cout); //operator<<(&s1,cout); cout << s1 << endl; //operator<<(cout, s1); }
前面之所以對(duì)空指針構(gòu)建對(duì)象提供一個(gè)空間的原因:使其在賦值重載中只有指向堆區(qū)一種情況進(jìn)行處理
通過此方式進(jìn)行等號(hào)運(yùn)算符重載,然后調(diào)動(dòng)拷貝構(gòu)造對(duì)s2進(jìn)行重寫構(gòu)造
輸出流重寫
class String { char* str; public: String(const char* p = NULL) :str(NULL) { if (p != NULL) { str = new char[strlen(p) + 1]; strcpy(str, p); } else { str = new char[1]; //額外提供一個(gè)空間 *str = '\0'; } } ~String() { if (str != NULL) { delete[] str; } str = NULL; } //ostream& operator<<(const String* const this, ostream &out) ostream& operator<<(ostream& out)const //重載插入操作符 { if (str != NULL) { out << str; } return out; } }; int main() { String s1("123"); s1 << cout; //s1.operator<<(cout); //operator<<(&s1,cout); }
在這里通過改寫前的代碼 operator<<(&s1,cout);
不難看出,將cout初始化out,隨后將this.str輸出至out
ostream& operator<<(ostream& out)const
此處只能使用引用,因?yàn)閏out在ostream類中進(jìn)行轉(zhuǎn)移,該類將拷貝構(gòu)造函數(shù)定義為保護(hù)訪問屬性,無法使用cout初始化out,繼而只能使用引用;同樣若我們不想使用實(shí)參去初始化形參,可以將拷貝構(gòu)造函數(shù)定義為私有或保護(hù)類型
若希望輸出符合cout << s1 << endl;
此種形式,需要再寫一個(gè)全局函數(shù)
class String { char* str; public: String(const char* p = NULL) :str(NULL) { if (p != NULL) { str = new char[strlen(p) + 1]; strcpy(str, p); } else { str = new char[1]; //額外提供一個(gè)空間 *str = '\0'; } } ~String() { if (str != NULL) { delete[] str; } str = NULL; } //ostream& operator<<(const String* const this, ostream &out) ostream& operator<<(ostream& out)const //重載插入操作符 { if (str != NULL) { out << str; } return out; } }; ostream& operator<<(ostream& out, const String& s) { s << out; //s.operator<<(cout); //operator<<(&s1,cout); return out; } int main() { String s1("123"); s1 << cout; //s1.operator<<(cout); //operator<<(&s1,cout); cout << s1 << endl; //operator<<(cout, s1); }
通過此種形式進(jìn)行翻轉(zhuǎn),繼而達(dá)到符合 cout << s1 << endl;
的形式
MyString加號(hào)運(yùn)算符重載
int main() { String s1("123"); String s2("456"); String s3; s3 = s1 + s2; S3 = s1 + "789"; s3 = "789" + s1; }
分別寫三個(gè)加號(hào)運(yùn)算符重載,來對(duì)應(yīng)上面的三個(gè)情況(類+類、類+字符串、字符串+類)
String operator+(const String& s)const { char *p = new char(strlen(this->str) + strlen(s.str) + 1); strcpy(p, this->str); strcat(p, s.str); return String(p); }
第一個(gè)為成員函數(shù),但是存在內(nèi)存泄漏,需要進(jìn)行下面的步驟
在私有成員變量中,創(chuàng)建一個(gè)新的構(gòu)造函數(shù),直接將p給到str,而沒有創(chuàng)建新的空間;并且在加號(hào)運(yùn)算符重載進(jìn)行修改使其調(diào)用私有的構(gòu)造函數(shù)
private: String(char*p,int)//兩個(gè)參數(shù)與公有構(gòu)造區(qū)分 { str = p; } public: String operator+(const String& s)const { char *p = new char(strlen(this->str) + strlen(s.str) + 1); strcpy(p, this->str); strcat(p, s.str); return String(p,1); }
這樣就解決了原本內(nèi)存泄漏的問題
接下來完成剩余兩個(gè)等號(hào)運(yùn)算符重載
String operator+(const char* s)const { char* p = new char(strlen(this->str) + strlen(s) + 1); strcpy(p, this->str); strcat(p, s); return String(p, 1); //return *this + String(s) //上面的方式更方便,但是會(huì)構(gòu)造兩個(gè)臨時(shí)對(duì)象 }
此處需要寫在類外,并且需要類內(nèi)添加友元函數(shù)
friend String operator+(const char* t, const String s);
String operator+(const char* t, const String s) { char* p = new char(strlen(s.str) + strlen(t) + 1); strcpy(p, s.str); strcat(p, t); return String(p, 1); //return String(p) + s; 與上面同理,并且不需要友元函數(shù) }
討論一個(gè)衍生問題
class String { private: char* str; public: String(const char* p = NULL) :str(NULL) { if (p != NULL) { str = new char[strlen(p) + 1]; strcpy(str, p); } else { str = new char[1]; //額外提供一個(gè)空間 *str = '\0'; } } ~String() { if (str != NULL) { delete[] str; } str = NULL; } String(const String& s) { //str = s.str; 淺拷貝 是同一個(gè)空間,會(huì)造成一個(gè)空間釋放兩次 //深拷貝 str = new char[strlen(s.str)]; strcpy(str, s.str); } String& operator=(const String& s) { if (this != &s) { delete[]str; str = new char[strlen(s.str)]; strcpy(str, s.str); } return *this; } }; String fun() { String s2("456"); return s2; } int main() { String s1; s1 = fun(); return 0; }
討論此程序執(zhí)行的過程總共創(chuàng)建了多少個(gè)對(duì)象:
主函數(shù)運(yùn)行首先開辟main函數(shù)棧幀,創(chuàng)建s1對(duì)象,默認(rèn)構(gòu)造只有大小為一的空間存放“\0”;之后執(zhí)行fun()函數(shù),分配fun棧幀,然后創(chuàng)建s2對(duì)象,創(chuàng)建一個(gè)堆區(qū),str指向堆區(qū)空間;并且將按值返回,需要構(gòu)建一個(gè)臨時(shí)對(duì)象(將亡值);
將亡值概念:表達(dá)式過程中所產(chǎn)生的不具有名字的一個(gè)實(shí)體,叫做將亡值;將亡值的生存期僅在表達(dá)式的調(diào)用過程中,表達(dá)式調(diào)用結(jié)束,將亡值就會(huì)結(jié)束
構(gòu)建臨時(shí)對(duì)象調(diào)用拷貝構(gòu)造,fun函數(shù)結(jié)束,s2生存期結(jié)束,調(diào)動(dòng)析構(gòu)函數(shù);首先釋放s2調(diào)用資源,再歸還s2空間;回到主函數(shù),把將亡值賦值給s1調(diào)用賦值語句,接著調(diào)用將亡值的析構(gòu)函數(shù)進(jìn)行釋放
這個(gè)過程中總共創(chuàng)建了三個(gè)對(duì)象,分別是s1、s2、將亡值對(duì)象
那么如果我們對(duì)fun以引用進(jìn)行返回
String& fun() { String s2("456"); return s2; } int main() { String s1; s1 = fun(); return 0; }
當(dāng)以引用返回,就不會(huì)返回一個(gè)s2的備份,從引用底層來看會(huì)返回s2的地址;這樣會(huì)從一個(gè)已死亡對(duì)象來獲取數(shù)據(jù),繼而會(huì)得到隨機(jī)值
隨后介紹的右值拷貝構(gòu)造與右值賦值語句可以解決這個(gè)問題
到此這篇關(guān)于C++實(shí)現(xiàn)MyString的示例代碼的文章就介紹到這了,更多相關(guān)C++ MyString內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ for循環(huán)與nullptr的小知識(shí)點(diǎn)分享
這篇文章主要是來和大家介紹一些C++中的小知識(shí)點(diǎn),本文分享的是for循環(huán)與nullptr,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-05-05C++實(shí)現(xiàn)簡單的HTTP服務(wù)器
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡單的HTTP服務(wù)器的相關(guān)資料,感興趣的朋友可以參考下2016-05-05QT中刪除信號(hào)于槽的連接的實(shí)現(xiàn)
本文主要介紹了QT中刪除信號(hào)于槽的連接的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06C++內(nèi)存管理之簡易內(nèi)存池的實(shí)現(xiàn)
大家好,本篇文章主要講的是C++內(nèi)存管理之簡易內(nèi)存池的實(shí)現(xiàn),感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下2021-12-12C語言統(tǒng)計(jì)輸入字符各個(gè)字母出現(xiàn)頻率的解題思路
這篇文章主要介紹了C語言統(tǒng)計(jì)輸入字符各個(gè)字母出現(xiàn)頻率的解題思路,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-08-08