欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

【ONE·C++||內(nèi)存管理和模板初階】-創(chuàng)新互聯(lián)

總言

??學(xué)習(xí)筆記,慢慢補(bǔ)充。

創(chuàng)新互聯(lián)主要從事網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)盂縣,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575文章目錄
  • 總言
  • 1、C/C++內(nèi)存分布
    • 1.1、內(nèi)存區(qū)域劃分簡(jiǎn)介
  • 2、動(dòng)態(tài)內(nèi)存分布管理
    • 2.1、C語言中動(dòng)態(tài)內(nèi)存管理:malloc、calloc、rellaooc、free
    • 2.2、C++中動(dòng)態(tài)內(nèi)存管理 :new、delete
      • 2.2.1、針對(duì)內(nèi)置類型
      • 2.2.2、針對(duì)自定義類型
      • 2.2.3、new申請(qǐng)動(dòng)態(tài)內(nèi)存失敗后如何處理
    • 2.2、operator new與operator delete全局函數(shù)
      • 2.2.1、關(guān)于new、delete功能的底層原理
      • 2.2.2、重載operator new與operator delete
      • 2.2.3、new、delete實(shí)現(xiàn)原理總結(jié)
    • 2.3、定位new
      • 2.3.1、是什么和為什么
  • 3、模板初階
    • 3.1、泛型編程
    • 3.2、函數(shù)模板
      • 3.2.1、函數(shù)模板的概念和基本使用方式
      • 3.2.2、函數(shù)模板底層原理
      • 3.2.3、函數(shù)模板的實(shí)例化:隱式、顯式等
      • 3.2.4、模板參數(shù)的匹配原則
    • 3.3、類模板
      • 3.3.1、為什么和是什么
      • 3.3.2、模板實(shí)例化說明
      • 3.3.3、以Stack的實(shí)現(xiàn)演示模板使用

??

1、C/C++內(nèi)存分布 1.1、內(nèi)存區(qū)域劃分簡(jiǎn)介

??1)、問題引入:

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{static int staticVar = 1;
	int localVar = 1;
	int num1[10] = {1, 2, 3, 4 };
	char char2[] = "abcd";
	const char* pChar3 = "abcd";
	int* ptr1 = (int*)malloc(sizeof(int) * 4);
	int* ptr2 = (int*)calloc(4, sizeof(int));
	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
	free(ptr1);
	free(ptr3);
}

在這里插入圖片描述選擇題:
??選項(xiàng): A、棧??B、堆 ??C、數(shù)據(jù)段(靜態(tài)區(qū)) ??D、代碼段(常量區(qū))

??1、globalVar在哪里?____ ??staticGlobalVar在哪里?____
??2、staticVar在哪里?____ ??localVar在哪里?____
??3、num1在哪里?____
??4、char2在哪里?____ ??*char2在哪里?___
??5、pChar3在哪里?____ ??*pChar3在哪里?____
??6、ptr1在哪里?____ ??*ptr1在哪里?____
在這里插入圖片描述

在這里插入圖片描述填空題:

??1、填空題:
??sizeof(num1)= ____??
??sizeof(char2)= ____??strlen(char2)= ____??
??sizeof(pChar3)= ____??strlen(pChar3)= ____??
??sizeof(ptr1)= ____??
??3、 sizeof 和 strlen 區(qū)別?
??
??
??
??2)、劃分區(qū)域示意圖:
在這里插入圖片描述

??
??
??

2、動(dòng)態(tài)內(nèi)存分布管理 2.1、C語言中動(dòng)態(tài)內(nèi)存管理:malloc、calloc、rellaooc、free

??此處詳細(xì)講解請(qǐng)看C動(dòng)態(tài)內(nèi)存章。
??
??

2.2、C++中動(dòng)態(tài)內(nèi)存管理 :new、delete

??1)、C++可以兼容C,為什么還需要提出自己的內(nèi)存管理方式?
?? 1、首先要明確的是,C++兼容C,故malloc、calloc、rellaooc、free這些在C++中照樣可以用。
?? 2、但有些地方,C中的動(dòng)態(tài)內(nèi)存管理方式就無能為力,而且使用起來比較麻煩,因此C++又提出了自己的內(nèi)存管理方式:通過new和delete操作符進(jìn)行動(dòng)態(tài)內(nèi)存管理
??
??

??

2.2.1、針對(duì)內(nèi)置類型

??1)、new、delete操作符針對(duì)內(nèi)置類型進(jìn)行動(dòng)態(tài)內(nèi)存管理的基本用法

?? 1、首先要明確的是,new、delete是關(guān)鍵字。而C語言中那套動(dòng)態(tài)內(nèi)存管理依賴的是函數(shù)。

在這里插入圖片描述如何開辟空間?

void Test()
{// 動(dòng)態(tài)申請(qǐng)一個(gè)int類型的空間
	int* ptr4 = new int;
	// 動(dòng)態(tài)申請(qǐng)一個(gè)int類型的空間并初始化為10
	int* ptr5 = new int(10);
	// 動(dòng)態(tài)申請(qǐng)10個(gè)int類型的空間
	int* ptr6 = new int[10];
}

int main(void)
{Test();
	return 0;
}

在這里插入圖片描述
?? 如何使用new開辟數(shù)組類型的空間?(即一次性同時(shí)生成多個(gè)類型相同的元素)
?? 該問題C++98不支持,C++11才支持,書寫方法如下:

void Test()
{//C++11:
	int* ptr1 = new int[10]{1,2,3 };
}

int main(void)
{Test();
	return 0;
}

在這里插入圖片描述

??
??

在這里插入圖片描述如何釋放空間?

void Test()
{// 動(dòng)態(tài)申請(qǐng)一個(gè)int類型的空間
	int* ptr4 = new int;
	// 動(dòng)態(tài)申請(qǐng)一個(gè)int類型的空間并初始化為10
	int* ptr5 = new int(10);
	// 動(dòng)態(tài)申請(qǐng)10個(gè)int類型的空間
	int* ptr6 = new int[10];
	delete ptr4;
	delete ptr5;
	delete[] ptr6;//單個(gè)對(duì)象直接delete,若是多個(gè)對(duì)象則使用[ ]


	//C++11:
	int* ptr1 = new int[10]{1,2,3 };
	delete[] ptr1;//單個(gè)對(duì)象直接delete,若是多個(gè)對(duì)象則使用[ ]
}

int main(void)
{Test();
	return 0;
}

??總結(jié):針對(duì)內(nèi)置類型,new、deletemalloc、free沒有本質(zhì)的區(qū)別,只有用法的區(qū)別。new、delete用法相對(duì)簡(jiǎn)化了。
??
??
??

2.2.2、針對(duì)自定義類型

??1)、new、delete針對(duì)自定義類型進(jìn)行動(dòng)態(tài)內(nèi)存管理的基本方法

class A
{public:
	A(int a = 0)
		: _a(a)
	{cout<< "A():"<< this<< endl;
	}

	~A()
	{cout<< "~A():"<< this<< endl;
	}

private:
	int _a;
};



int main()
{// 1、堆上申請(qǐng)空間
	A* p1 = (A*)malloc(sizeof(A));
	if (p1 == NULL)
	{perror("malloc fail");
		return 0;
	}

	// 1、釋放空間
	free(p1);

	// 1、堆上申請(qǐng)空間  2、調(diào)用構(gòu)造函數(shù)初始化
	A* p2 = new A;
	A* p2 = new A(10);

	// 1、調(diào)用析構(gòu)函數(shù)清理對(duì)象中資源 2、釋放空間
	delete p2;

	cout<< endl<< endl;

	A* p3 = new A[2];
	delete[] p3;

	//C++11支持
	A* p3 = new A[2]{1,2 };
	A* p3 = new A[2]{A(1), A(2) };

	// 結(jié)論:new/delete 是為自定義類型準(zhǔn)備的。
	// 不僅在對(duì)申請(qǐng)出來,還會(huì)調(diào)用構(gòu)造和析構(gòu)初始化和清理

	return 0;
}

在這里插入圖片描述malloc、free對(duì)自定義類型

?? 1、對(duì)自定義類型使用malloc、free申請(qǐng)和釋放空間:并不會(huì)對(duì)自定義類型初始化。

// 1、堆上申請(qǐng)空間
	A* p1 = (A*)malloc(sizeof(A));
	if (p1 == NULL)
	{perror("malloc fail");
		return 0;
	}
		// 1、釋放空間
	free(p1);

在這里插入圖片描述new、delete對(duì)自定義類型

?? 1、使用new動(dòng)態(tài)申請(qǐng)自定義類型,會(huì)調(diào)用默認(rèn)構(gòu)造函數(shù)初始化。
?? 2、若類不提供默認(rèn)構(gòu)造,若要編譯通過,則需要自己傳參。

// 1、堆上申請(qǐng)空間  2、調(diào)用構(gòu)造函數(shù)初始化
	A* p2 = new A;//這種寫法需要有默認(rèn)構(gòu)造
	A* p2 = new A(10);//如果沒有默認(rèn)構(gòu)造則需要我們手動(dòng)傳參
	delete p2;

?? 3、相比于free,delete會(huì)調(diào)用析構(gòu)函數(shù)清理對(duì)象中的資源(但是否需要這是取決于析構(gòu)函數(shù)本身)

A* p3 = new A[2];
	delete[] p3;

??4、若是沒有默認(rèn)構(gòu)造,多個(gè)自定義類型需要傳參的寫法(一種是構(gòu)造(隱式類型)、一種是拷貝構(gòu)造:

//C++11支持
	A* p3 = new A[2]{1,2 };
	A* p3 = new A[2]{A(1), A(2) };	

	delete[] p3;

?? 結(jié)論:new/delete 是為自定義類型準(zhǔn)備的。不僅在對(duì)申請(qǐng)出來,還會(huì)調(diào)用構(gòu)造和析構(gòu)初始化和清理.

??
??2)、delete、new構(gòu)造、析構(gòu)順序探索
??對(duì)于多個(gè)自定義類型,此處需要注意構(gòu)造和析構(gòu)的順序,以及在堆上的地址排序。

class A
{public:
	A(int a = 0)
		: _a(a)
	{cout<< "A():"<< this<< endl;
	}

	~A()
	{cout<< "~A():"<< this<< endl;
	}

private:
	int _a;
};
int main()
{A* p1 = new A[10];
	cout<< endl;
	delete[] p1;
	return 0;
}

在這里插入圖片描述

??
??

2.2.3、new申請(qǐng)動(dòng)態(tài)內(nèi)存失敗后如何處理
int main()
{//C: 失敗返回NULL
	char* p1 = (char*)malloc(1024u * 1024u * 1024u * 2 - 1);//u表示無符號(hào)
	//cout<< p1<< endl;//cout自動(dòng)識(shí)別類型,會(huì)先去解引用字符指針,而非取地址。
	printf("%p\n", p1);

	//C++: new失敗,不需要檢查返回值,他失敗是拋異常
	try
	{//申請(qǐng)空間失敗的一種寫法:
		char* p2 = new char[1024u * 1024u * 1024u * 2 - 1];//此處失敗會(huì)直接跳轉(zhuǎn)后續(xù)catch部分,不會(huì)指向下一行。
		printf("%p\n", p2);
		///申請(qǐng)空間失敗的另一種方法:
		size_t n = 0;
		while (1)
		{	char* p2 = new char[1024];
			++n;

			printf("%p->[%d]\n", p2, n);
		}
	}
	catch (const exception& e)//捕獲異常
	{cout<< e.what()<< endl;
	}

	return 0;
}

??
??
??

2.2、operator new與operator delete全局函數(shù) 2.2.1、關(guān)于new、delete功能的底層原理

?? 1、new和delete是用戶進(jìn)行動(dòng)態(tài)內(nèi)存申請(qǐng)和釋放的操作符,operator new 和operator delete是 系統(tǒng)提供的全局函數(shù),new在底層調(diào)用operator new全局函數(shù)來申請(qǐng)空間,delete在底層通過 operator delete全局函數(shù)來釋放空間。
??2、而operator new 實(shí)際也是通過malloc來申請(qǐng)空間,如果 malloc申請(qǐng)空間成功就直接返回,否則執(zhí)行用戶提供的空間不足應(yīng)對(duì)措施,如果用戶提供該措施 就繼續(xù)申請(qǐng),否則就拋異常。operator delete 最終是通過free來釋放空間的。
??
??

2.2.2、重載operator new與operator delete

??1、 一般情況下不需要對(duì) operator new 和 operator delete進(jìn)行重載,除非在申請(qǐng)和釋放空間時(shí)候有某些特殊的需求。比如:在使用new和delete申請(qǐng)和釋放空間時(shí),打印一些日志信息,可以簡(jiǎn)單幫助用戶來檢測(cè)是否存在內(nèi)存泄漏。

??2、關(guān)于專屬的operator new的實(shí)現(xiàn):可用于頻繁調(diào)用new需要提高效率的情況

// new ->operator new + 構(gòu)造函數(shù)
// 默認(rèn)情況下operator new使用全局庫里面
// 每個(gè)類可以去實(shí)現(xiàn)自己專屬operator new  new這個(gè)類對(duì)象,就會(huì)調(diào)自己實(shí)現(xiàn)這個(gè)operator new

// 實(shí)現(xiàn)一個(gè)類專屬的operator new  -- 了解一下
struct ListNode
{int _val;
	ListNode* _next;

	// 內(nèi)存池
	static allocatoralloc;//靜態(tài)成員變量

	void* operator new(size_t n)//重載專屬的operator new
	{cout<< "operator new ->STL內(nèi)存池allocator申請(qǐng)"<< endl;
		void* obj = alloc.allocate(1);
		return obj;
	}

	void operator delete(void* ptr)//重載專屬的operator delete
	{cout<< "operator delete ->STL內(nèi)存池allocator申請(qǐng)"<< endl;

		alloc.deallocate((ListNode*)ptr, 1);
	}

	struct ListNode(int val)
		:_val(val)
		, _next(nullptr)
	{}
};

// allocator以后會(huì)講,現(xiàn)在先會(huì)用即可
allocatorListNode::alloc;//類外定義

int main()
{// 頻繁申請(qǐng)ListNode. 想提高效率 -- 申請(qǐng)ListNode時(shí),不去malloc,而是自己定制內(nèi)存池
	ListNode* node1 = new ListNode(1);//new相對(duì)于malloc簡(jiǎn)化
	ListNode* node2 = new ListNode(2);
	ListNode* node3 = new ListNode(3);

	delete node1;
	delete node2;
	delete node3;

	return 0;
}

??
??

2.2.3、new、delete實(shí)現(xiàn)原理總結(jié)

在這里插入圖片描述
??
??

2.3、定位new 2.3.1、是什么和為什么

??1)、場(chǎng)景引入:

class A
{public:
	A(int a = 0)
		: _a(a)
	{cout<< "A():"<< this<< endl;
	}

	~A()
	{cout<< "~A():"<< this<< endl;
	}

private:
	int _a;
};

int main()
{A* p1 = new A;

	A* p2 = (A*)malloc(sizeof(A));
	if (p2 == nullptr)
	{perror("malloc fail");
	}
	return 0;
}

??如上述代碼:有時(shí)我們需要對(duì)已經(jīng)定義的類進(jìn)行初始化。而我們知道,類初始化需要調(diào)用構(gòu)造函數(shù),目前已知的兩種構(gòu)造函數(shù)調(diào)用方式是,①在定義類時(shí)會(huì)調(diào)用構(gòu)造函數(shù)初始化成員;②通過new開辟自定義類型也會(huì)進(jìn)過構(gòu)造函數(shù)。
??那么,針對(duì)上述p2這樣已經(jīng)申請(qǐng)好的類,成員變量私有情況下,如何為它初始化?

??
??2)、是什么和怎么用:
??概念:
??定位new表達(dá)式是在已分配的原始內(nèi)存空間中調(diào)用構(gòu)造函數(shù)初始化一個(gè)對(duì)象。
??使用格式:
??new (place_address) type或者new (place_address) type(initializer-list)
??①place_address必須是一個(gè)指針
??②initializer-list是類型的初始化列表
??
?? 演示:

new(p2)A;
	new(p2)A(10);
class A
{public:
	A(int a = 0)
		: _a(a)
	{cout<< "A():"<< this<< endl;
	}

	~A()
	{cout<< "~A():"<< this<< endl;
	}

private:
	int _a;
};

int main()
{A* p1 = new A;

	A* p2 = (A*)malloc(sizeof(A));
	if (p2 == nullptr)
	{perror("malloc fail");
	}
	new(p2)A;//方法一
	new(p2)A(10);//方法二

	return 0;
}

??
??3)、為什么用:
??使用場(chǎng)景:
??定位new表達(dá)式在實(shí)際中一般是配合內(nèi)存池使用。因?yàn)閮?nèi)存池分配出的內(nèi)存沒有初始化,所以如果是自定義類型的對(duì)象,需要使用new的定義表達(dá)式進(jìn)行顯示調(diào)構(gòu)造函數(shù)進(jìn)行初始化。
??
??
??

3、模板初階 3.1、泛型編程

??1)、關(guān)于為什么要有泛型編程的引入說明:

void Swap(int& left, int& right)
{int temp = left;
	left = right;
	right = temp;
}

void Swap(double& left, double& right)
{double temp = left;
	left = right;
	right = temp;
}

void Swap(char& left, char& right)
{char temp = left;
	left = right;
	right = temp;
}

int main()
{int i = 1, j = 2;
	double x = 1.1, y = 2.2;
	Swap(i, j);
	Swap(x, y);

	char m = 'A', n = 'B';
	Swap(m, n);

	return 0;
}

?? 類似于上述Swap交換函數(shù),雖然我們也可以通過typedef重命名來更換類型,但如果出現(xiàn)多個(gè)類型同時(shí)需要使用Swap函數(shù)時(shí),typedef仍舊不能很好的解決問題。
在這里插入圖片描述

?? 因此,我們提出了泛型編程。
??泛型編程: 編寫與類型無關(guān)的通用代碼,是代碼復(fù)用的一種手段。模板是泛型編程的基礎(chǔ)。

??
??
??
??

3.2、函數(shù)模板 3.2.1、函數(shù)模板的概念和基本使用方式

??template
??返回值類型 函數(shù)名(參數(shù)列表){}

?? 實(shí)例演示:

templatevoid Swap(T& left, T& right)
{T tmp = left;
	left = right;
	right = tmp;
}

?? 1、typename后面類型名字T是隨便取,Ty、K、V,一般是大寫字母或者單詞首字母大寫
??2、T 代表是一個(gè)模板類型(虛擬類型)
??3、注意:typename是用來定義模板參數(shù)關(guān)鍵字,也可以使用class(切記:不能使用struct代替class)

template//此處typename與class只有一些細(xì)微區(qū)別,后面再講述
void Swap(T& left, T& right)
{T tmp = left;
	left = right;
	right = tmp;
}

??演示如下:此處有一個(gè)問題,我們用不同類型的變量去調(diào)用這個(gè)函數(shù)模板時(shí),所生成的Swap函數(shù)是不是同一個(gè)?
在這里插入圖片描述

??
??

3.2.2、函數(shù)模板底層原理

??1)、問題引入:
??接上文:
在這里插入圖片描述

??
??2)、總述:
在這里插入圖片描述

??
??

3.2.3、函數(shù)模板的實(shí)例化:隱式、顯式等

??1)、函數(shù)模板實(shí)例化·隱式實(shí)例化中一個(gè)容易出錯(cuò)的問題

templateT Add(const T& left, const T& right)
{return left + right;
}

int main()
{int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, a2);//right
	Add(d1, d2);//right

	Add(a1, d1);//error

	return 0;
}

在這里插入圖片描述

??隱式實(shí)例化中編譯報(bào)錯(cuò)的場(chǎng)景之一:
??報(bào)錯(cuò)原因并非不能隱式類型轉(zhuǎn)換(事實(shí)上C++沿襲C,不用模板我們自己寫Add時(shí)是成功的),此處報(bào)錯(cuò)的真正原因在于推演實(shí)例化報(bào)錯(cuò)。即無法確定需要轉(zhuǎn)換到哪個(gè)類型。
??
??
??2)、如何解決隱式實(shí)例化中這類問題?

在這里插入圖片描述解決方案一:強(qiáng)制類型轉(zhuǎn)換

??演示如下:

templateT Add(const T& left, const T& right)
{return left + right;
}

int main()
{//編譯器自動(dòng)推演,隱式實(shí)例化
	cout<< Add(1, 2)<< endl;
	cout<< Add((int)1.1, 2)<< endl;
	cout<< Add(1.1, (double)2)<< endl;

	return 0;
}

在這里插入圖片描述

??
??

在這里插入圖片描述解決方案二:顯示實(shí)例化

??顯式實(shí)例化:在函數(shù)名后的<>中指定模板參數(shù)的實(shí)際類型

templateT Add(const T& left, const T& right)
{return left + right;
}

int main()
{//顯式實(shí)例化:在函數(shù)名后的<>中指定模板參數(shù)的實(shí)際類型
	cout<< Add(1, 2)<< endl;
	cout<< Add(1.1, 2)<< endl;
	cout<< Add(1.1, 2)<< endl;

	return 0;
}

??1、此處模板類型有幾個(gè),顯示實(shí)例化時(shí),實(shí)際類型就要寫幾個(gè)。
??2、如果類型不匹配,編譯器會(huì)嘗試進(jìn)行隱式類型轉(zhuǎn)換,如果無法轉(zhuǎn)換成功編譯器將會(huì)報(bào)錯(cuò)。

在這里插入圖片描述

??
??
??

在這里插入圖片描述解決方案三:使用多個(gè)模板類型

templateT1 Add(const T1& left, const T2& right)
{return left + right;
}

int main()
{cout<< Add(1, 2)<< endl;
	cout<< Add(1.1, 2)<< endl;
	cout<< Add(2, 1.1)<< endl;//要注意理解此處細(xì)節(jié):參與Add時(shí)仍舊會(huì)發(fā)生隱式類型轉(zhuǎn)換為double,只是返回類型為int
	return 0;
}

在這里插入圖片描述

??
??
??3)、一些必須顯示實(shí)例化的場(chǎng)景說明

templateT* Func(int n)
{T* a = new T[n];
	return a;
}

class A{};

int main()
{// 必須顯示實(shí)例化才能調(diào)用
	Func(10);//此處是因?yàn)閭魅氲膮?shù)為int型,而實(shí)際T需要返回類型為類A,因此在此處指定實(shí)際類型為A。

	return 0;
}

??
??

3.2.4、模板參數(shù)的匹配原則

??1)、關(guān)于函數(shù)模板、非模板函數(shù)同時(shí)存在時(shí),如何調(diào)用的問題?
??回答:如何有匹配的非模板函數(shù),率先調(diào)用該函數(shù),若沒有,則調(diào)用模板函數(shù)。

??

在這里插入圖片描述演示實(shí)例一:

?? 一個(gè)非模板函數(shù)可以和一個(gè)同名的函數(shù)模板同時(shí)存在,而且該函數(shù)模板還可以被實(shí)例化為這個(gè)非模板函數(shù)。

// 專門處理int的加法函數(shù)
int Add(int left, int right)
{return left + right;
}
// 通用加法函數(shù)
templateT Add(T left, T right)
{return left + right;
}
void Test()
{Add(1, 2); // 有匹配的非模板函數(shù),不會(huì)調(diào)用模板
	Add(1.1, 2.2);// 沒有匹配的非模板函數(shù),會(huì)去調(diào)用模板
	Add(1, 2); // 調(diào)用編譯器特化的模板
}

int main()
{Test();
	return 0;
}

??

在這里插入圖片描述演示實(shí)例二:

?? 對(duì)于非模板函數(shù)和同名函數(shù)模板,如果其他條件都相同,在調(diào)動(dòng)時(shí)會(huì)優(yōu)先調(diào)用非模板函數(shù)而不會(huì)從該模板產(chǎn)生出一個(gè)實(shí)例。如果模板可以產(chǎn)生一個(gè)具有更好匹配的函數(shù), 那么將選擇模板。

// 專門處理int的加法函數(shù)
int Add(int left, int right)
{return left + right;
}
// 通用加法函數(shù)
templateT1 Add(T1 left, T2 right)
{return left + right;
}
void Test()
{Add(1, 2); // 與非函數(shù)模板類型完全匹配,不需要函數(shù)模板實(shí)例化
	Add(1, 2.0); // 模板函數(shù)可以生成更加匹配的版本,編譯器根據(jù)實(shí)參生成更加匹配的Add函數(shù)
}

int main()
{Test();
	return 0;
}

??
??

3.3、類模板 3.3.1、為什么和是什么

??1)、為什么需要類模板的引入?
在這里插入圖片描述

class Stacki
{private:
	int* _a;
	int top;
	int capacity;
};

class Stackc
{private:
	char* _a;
	int top;
	int capacity;
};

int main()
{Stackc st1; // char
	Stacki st2; // int

	return 0;
}
typedef char STDataType;//此處修改類型
class Stack
{private:
	STDataType* _a;
	int top;
	int capacity;
};

int main()
{Stack st1; // char
	Stack st2; // char

	return 0;
}

??
??
??2)、類模板如何使用?
?? 類模板格式說明:

templateclass 類模板名
{// 類內(nèi)成員定義
};

??
??3)、以類模板定義Stack舉例說明使用細(xì)節(jié):各類知識(shí)雜糅與理解
??總體演示:

template//用模板定義一個(gè)類
class Stack
{public:
	//構(gòu)造函數(shù)
	Stack(size_t capacity = 4)//缺省值
		: _a(nulltpr)//初始化列表:默認(rèn)先處理為這樣子
		, _top(0)
		, _capacity(0)
	{if (capacity >0)//雖然給了缺省值,但也有可能實(shí)參傳遞進(jìn)來的是0
		{	//為_a開辟空間,此處使用了new,注意new的用法以及new多個(gè)空間時(shí)[]中傳入的數(shù)據(jù)
			_a = new T[capacity];//此處不需要檢查new是否失敗,因?yàn)榭梢允褂脪伄惓ry\catch
			_capacity = capacity;
			_top = 0;
		}
	}
	private:
	T* _a;
	size_t _top;
	size_t _capacity;
};
int main()
{//用同一個(gè)類模板顯示實(shí)例化
	//不過Stack、Stack是不同的兩個(gè)類型
	Stackstr1;
	Stackstr2;

	//關(guān)于缺省值:如果我們能具體知道capacity值,就能這樣直接傳入
	//若不知曉,就可以使用缺省值中給定的。
	Stackstr3(100);

	//關(guān)于初始化列表中的_capacity是為了處理這樣的情況:
	Stackstr4(0);
	//若沒有它,上述構(gòu)造函數(shù)中進(jìn)不了if語句,而_capacity沒有初始化,
	//那么得到的str4實(shí)際上_capacity得到的是默認(rèn)隨機(jī)值,
	//而我們插入數(shù)據(jù)時(shí)擴(kuò)容卻是看_top==_capacity的
	//這樣就出了問題
}

??細(xì)節(jié)解釋一:自定義類型的模板定義需要顯式實(shí)例化:即這里需要理解模板定義出來的類型T需要用到哪里。

//用同一個(gè)類模板顯式實(shí)例化
	//不過Stack、Stack是不同的兩個(gè)類型
	Stackstr1;
	Stackstr2;

??細(xì)節(jié)解釋二:初始化列表處,_capacity(0)這些是否要處理?

Stack(size_t capacity = 4)//缺省值
		: _a(nulltpr)//初始化列表:
		, _top(0)
		, _capacity(0)
		{}

??回答:需要。構(gòu)造函數(shù)中我們給予的只是缺省值,如果顯示穿參并且參數(shù)為0時(shí),會(huì)導(dǎo)致_capacity處為隨機(jī)值,那么后續(xù)會(huì)遇到各種麻煩。

//關(guān)于初始化列表中的_capacity是為了處理這樣的情況:
	Stackstr4(0);
	//若沒有它,上述構(gòu)造函數(shù)中進(jìn)不了if語句,而_capacity沒有初始化,
	//那么得到的str4實(shí)際上_capacity得到的是默認(rèn)隨機(jī)值,
	//而我們插入數(shù)據(jù)時(shí)擴(kuò)容卻是看_top==_capacity的
	//這樣就出了問題

??細(xì)節(jié)解釋三:如果不在初始化列表給值,也可以在private成員變量中給,即使用C++打的補(bǔ)丁,但本質(zhì)上是一樣的。

private:
	T* _a =nullptr;
	size_t _top =0;
	size_t _capacity =0;

??
??

3.3.2、模板實(shí)例化說明

??模板不支持聲明和定義跨文件分離。若是覺得放在類中形成內(nèi)聯(lián)不方便,則可在同文件中進(jìn)行聲明和定義分離。
??同文件中的聲明和定義分離,注意類模板的寫法。
在這里插入圖片描述

??
??

3.3.3、以Stack的實(shí)現(xiàn)演示模板使用

??

templateclass Stack
{public:
	//構(gòu)造函數(shù)
	Stack(size_t capacity = 4)//缺省值
		:_a(nulltpr)//初始化列表:默認(rèn)先處理為這樣子
		, _top(0)
		, _capacity(0)
	{if (capacity >0)//雖然給了缺省值,但也有可能實(shí)參傳遞進(jìn)來的是0
		{	//為_a開辟空間,此處使用了new,注意new的用法以及new多個(gè)空間時(shí)[]中傳入的數(shù)據(jù)
			_a = new T[capacity];//此處不需要檢查new是否失敗,因?yàn)榭梢允褂脪伄惓ry\catch
			_capacity = capacity;
			_top = 0;
		}
	}

	//析構(gòu)函數(shù)
	~Stack()
	{//需要手動(dòng)釋放動(dòng)態(tài)內(nèi)存空間
		delete[] _a;//使用delete時(shí)需要注意加括號(hào)
		//后續(xù)置空這個(gè)步驟不影響
		_a = nullptr;
		_capacity = _top = 0;
	}

	//拷貝構(gòu)造:此處設(shè)計(jì)深淺拷貝,后續(xù)講解


	void Push(const T& x);//此處再次體現(xiàn)泛型模板,因?yàn)椴迦霐?shù)據(jù)類型為T


	//刪除
	void Pop()
	{assert(_top >0);
		--_top;
	}

	//判空
	bool Empty()
	{return _top == 0;
	}

	//取棧頂元素
	const T& Top()
	{//此處_a中的數(shù)據(jù)屬于堆上動(dòng)態(tài)開辟的,因此可以使用引用傳值返回
	//此處加入const是為了防止引用返回后將棧頂元素修改

		assert(_top >0);
		return _a[_top - 1];
	}

private:
	T* _a;
	size_t _top;
	size_t _capacity;
};




//棧頂插入:
//此處再次體現(xiàn)泛型模板,因?yàn)椴迦霐?shù)據(jù)類型為T
{//檢查擴(kuò)容
	//有兩種可能性:第一,空間已滿;第二,空間未開辟
	if (_top == _capacity)
	{// 1、開新空間
		// 2、拷貝數(shù)據(jù)
		// 3、釋放舊空間
		size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;

		//擴(kuò)容需要重新開辟空間,以前我們學(xué)習(xí)的是malloc和realloc,能原地?cái)U(kuò)容或者系統(tǒng)自己解決
		//現(xiàn)在我們使用new、delete,其不能自動(dòng)解決空間問題,因此需要我們手動(dòng)處理
		T* tmp = new T[newcapacity];
		//引出問題:為什么C++中我們推薦使用new、delet?
		//回答:此處使用的是類模板,其模板類型T有可能是自定義類型
		//malloc對(duì)自定義類型在申請(qǐng)空間時(shí)不會(huì)初始化。

		//開了新空間,需要對(duì)舊空間進(jìn)行處理
		if (_a)//這里是用來檢查是否為第一次擴(kuò)容,因?yàn)槭状螖U(kuò)容就不存在搬動(dòng)空間問題
		{	//要將舊空間中的數(shù)據(jù)拷貝到新空間里
			memcpy(tmp, _a, sizeof(T) * _top);//注意memcpy的使用參數(shù)含義
			//釋放舊空間
			delet[] _a;
		}
		//改變指向關(guān)系
		_a = tmp;
		_capacity = newcapacity;
	}

	_a[_top] = x;
	++_top;
}

??
??

??
??
??

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

新聞名稱:【ONE·C++||內(nèi)存管理和模板初階】-創(chuàng)新互聯(lián)
鏈接地址:http://aaarwkj.com/article0/codgoo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、網(wǎng)站設(shè)計(jì)公司、網(wǎng)頁設(shè)計(jì)公司品牌網(wǎng)站建設(shè)、網(wǎng)站維護(hù)、建站公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐ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)站制作
一区二区亚洲国产精品| 成人在线一区二区三区观看| 草草影院最新地址在线观看| 日韩欧美精品在线不卡| 午夜激情在线观看国产| 开心久久婷婷综合中文字幕| 91亚洲蜜臀精品国产| 未满十八周岁禁看视频| 国产精品大屁股一区二区| 一起草草视频在线观看| 无套内射精品一区二区| 国产欧美日韩在线高清| 久久99久久久久久精品| 免费在线观看做性小视频| 日韩精品人妻一区二区三区蜜桃臀 | 男人午夜影视在线观看| 国产一区二区精品不卡| 欧美成人极品一区二区三区| 亚洲国产精品va在线香蕉| 久久精品国产亚洲av热老太| 97精品免费在线观看| 国产精品一区二区三区熟女| 99热免费精品在线观看| 国产女孩精品在线播放| 国产精品久久亚洲一区二区| 偷拍视频一区二区三区| 中文字幕熟妇人妻av在线| 亚洲一区二区三区日韩精品| 七月丁香色婷婷婷基地| 日本黄色中文字幕网站| 中文字幕乱码人妻一区| 插入内射视频在线观看| 亚洲成人自拍在线视频| av天天堂网在线播放| 国内精品人妻在线中文字幕| 国产精品又大又黑又长又粗| 一本色道久久88综合日韩| 欧美日本一区二区四区| 日本熟女午夜福利视频| 日本大型午夜福利视频| 日韩欧美国产精品一区二区|