最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++實(shí)現(xiàn)MyString的示例代碼

 更新時(shí)間:2022年02月17日 14:19:45   作者:悲傷土豆拌飯  
本文主要介紹了C++實(shí)現(xiàn)MyString的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

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è)空間,會造成一個(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);
}

前面之所以對空指針構(gòu)建對象提供一個(gè)空間的原因:使其在賦值重載中只有指向堆區(qū)一種情況進(jìn)行處理

在這里插入圖片描述

通過此方式進(jìn)行等號運(yùn)算符重載,然后調(diào)動拷貝構(gòu)造對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加號運(yùn)算符重載

int main()
{
	String s1("123");
	String s2("456");

	String s3;
	s3 = s1 + s2;
	S3 = s1 + "789";
	s3 = "789" + s1;
}

分別寫三個(gè)加號運(yùn)算符重載,來對應(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)建新的空間;并且在加號運(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è)等號運(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)
	//上面的方式更方便,但是會構(gòu)造兩個(gè)臨時(shí)對象
}

此處需要寫在類外,并且需要類內(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è)空間,會造成一個(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è)對象:

在這里插入圖片描述

主函數(shù)運(yùn)行首先開辟main函數(shù)棧幀,創(chuàng)建s1對象,默認(rèn)構(gòu)造只有大小為一的空間存放“\0”;之后執(zhí)行fun()函數(shù),分配fun棧幀,然后創(chuàng)建s2對象,創(chuàng)建一個(gè)堆區(qū),str指向堆區(qū)空間;并且將按值返回,需要構(gòu)建一個(gè)臨時(shí)對象(將亡值);

將亡值概念:表達(dá)式過程中所產(chǎn)生的不具有名字的一個(gè)實(shí)體,叫做將亡值;將亡值的生存期僅在表達(dá)式的調(diào)用過程中,表達(dá)式調(diào)用結(jié)束,將亡值就會結(jié)束

構(gòu)建臨時(shí)對象調(diào)用拷貝構(gòu)造,fun函數(shù)結(jié)束,s2生存期結(jié)束,調(diào)動析構(gòu)函數(shù);首先釋放s2調(diào)用資源,再歸還s2空間;回到主函數(shù),把將亡值賦值給s1調(diào)用賦值語句,接著調(diào)用將亡值的析構(gòu)函數(shù)進(jìn)行釋放

這個(gè)過程中總共創(chuàng)建了三個(gè)對象,分別是s1、s2、將亡值對象

那么如果我們對fun以引用進(jìn)行返回

String& fun()
{
	String s2("456");
	return s2;
}
int main()
{
	String s1;
	s1 = fun();
	
	return 0;
}

當(dāng)以引用返回,就不會返回一個(gè)s2的備份,從引用底層來看會返回s2的地址;這樣會從一個(gè)已死亡對象來獲取數(shù)據(jù),繼而會得到隨機(jī)值

在這里插入圖片描述

隨后介紹的右值拷貝構(gòu)造與右值賦值語句可以解決這個(gè)問題

到此這篇關(guān)于C++實(shí)現(xiàn)MyString的示例代碼的文章就介紹到這了,更多相關(guān)C++ MyString內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

栾川县| 黎城县| 于都县| 望都县| 宜宾县| 马关县| 石嘴山市| 南漳县| 马鞍山市| 聂拉木县| 酒泉市| 南昌县| 阿鲁科尔沁旗| 永济市| 乌拉特中旗| 珲春市| 三明市| 清涧县| 泰宁县| 玛曲县| 林口县| 扎兰屯市| 区。| 大新县| 宿松县| 资溪县| 烟台市| 喀什市| 江西省| 怀集县| 崇左市| 平昌县| 丹寨县| 奎屯市| 海城市| 沅陵县| 同德县| 平泉县| 石河子市| 抚远县| 武清区|