欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++適用入門同學(xué)的模板講解

 更新時間:2022年07月14日 08:58:55   作者:Yuucho  
人們需要編寫多個形式和功能都相似的函數(shù),因此有了函數(shù)模板來減少重復(fù)勞動;人們也需要編寫多個形式和功能都相似的類,于是?C++?引人了類模板的概念,編譯器從類模板可以自動生成多個類,避免了程序員的重復(fù)勞動

1. 泛型編程

C++下一個針對C語言不足而設(shè)計的語法就叫作模板,模板的這種思想叫作泛型編程。

泛型編程的意思是:

我們以前C語言寫代碼是不是都是針對一種類型,比如我們寫個Swap,寫個排序,我們換一個類型,程序都得掛。

而泛型編程不再是針對某種類型,能夠適應(yīng)廣泛的類型。泛型編程用的一個東西就叫作模板。

博主先帶大家來舉一個簡單的范例:

如何實現(xiàn)一個通用的交換函數(shù)呢?

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;
}
......

即使C++有函數(shù)重載,寫一個Swap是不是也要寫很多的代碼呀!但是這些代碼都是相似的,int要寫一個,double要寫一個,char要寫一個,日期類要寫一個,自定義類型都得寫一個,全部都得寫一個。有意思沒?

ok,C++就給出了一個模板,讓編譯器根據(jù)不同的實參類型自動推導(dǎo)生成相應(yīng)的一系列類似的代碼。

模板是將一個事物的結(jié)構(gòu)規(guī)律予以固定化、標(biāo)準(zhǔn)化的成果,它體現(xiàn)的是結(jié)構(gòu)形式的標(biāo)準(zhǔn)化。

模板分為函數(shù)模板和類模板:

2. 函數(shù)模板

2.1 函數(shù)模板概念

函數(shù)模板代表了一個函數(shù)家族,該函數(shù)模板與類型無關(guān),在使用時被參數(shù)化,根據(jù)實參類型產(chǎn)生函數(shù)的特定類型版本。

2.2 函數(shù)模板格式

注意:typename是用來定義模板參數(shù)關(guān)鍵字,也可以使用class(切記:不能使用struct代替class)

template<typename T1, typename T2,......,typename Tn>

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

template<typename T>
void Swap( T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

然后我們可以這樣調(diào)用:

int main()
{
	int a = 0, b = 1;
	double c = 2.2, d = 3.3;
	Swap(a, b);
	Swap(c, d);
	printf("a=%d b=%d\n", a, b);
	printf("c=%lf d=%lf\n", c, d);
	return 0;
}

愛思考的同學(xué)可能就會問這個函數(shù)模板到底是怎么做到的呢?

大家猜一猜這兩個Swap調(diào)用的是不是同一個函數(shù)?

ok,博主告訴大家,它們調(diào)用的肯定不是同一個函數(shù)。雖然它們看起是來調(diào)用了同一個函數(shù)(這是編譯器優(yōu)化的結(jié)果),但是它們調(diào)用的是模板自動生成的相應(yīng)函數(shù)。

2.3 函數(shù)模板的原理

函數(shù)模板是一個藍(lán)圖,它本身并不是函數(shù),是編譯器用使用方式產(chǎn)生特定具體類型函數(shù)的模具。

所以其實模板就是將本來應(yīng)該我們做的重復(fù)的事情交給了編譯器。

模板的實例化:

在編譯器編譯階段,對于模板函數(shù)的使用,編譯器需要根據(jù)傳入的實參類型來推演生成對應(yīng)類型的函數(shù)以供調(diào)用。比如:當(dāng)用double類型使用函數(shù)模板時,編譯器通過對實參類型的推演,將T確定為double類型,然后產(chǎn)生一份專門處理double類型的代碼,對于字符類型也是如此。

其實swap這個常用的小函數(shù),C++的庫里面有提供。大家想一想為什么C語言不提供,因為C語言沒辦法提供,這是C語言語法的缺陷。

2.4 函數(shù)模板的實例化

用不同類型的參數(shù)使用函數(shù)模板時,稱為函數(shù)模板的實例化。模板參數(shù)實例化分為:隱式實例化和顯式實例化。

2.4.1顯式實例化

講到這,博主問大家一個問題:函數(shù)模板一定就是推演的嗎?不一定。

假設(shè),我們寫了一個沒有參數(shù)或者沒有用模板參數(shù)的func函數(shù),我們該怎么調(diào)用?

template<class T>  
T* func(int n)
{
	return new T[n];
}
int main()
{
	int* p1 = func(10);
	double* p2 = func(10);
	return 0;
}

我們這樣調(diào)用,編譯器能不能知道T的類型?是不是肯定不行呀:

這個時候函數(shù)模板就需要顯示實例化:在函數(shù)名后的<>中指定模板參數(shù)的實際類型。

模板參數(shù)很多用法和函數(shù)參數(shù)是很像的,也可以有缺省參數(shù)。只是說模板參數(shù)傳遞的是類型,函數(shù)參數(shù)傳遞的是對象值。

2.4.2 隱式實例化

讓編譯器根據(jù)實參推演模板參數(shù)的實際類型

template<class T>
T 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);
	Add(d1, d2);
}

那如果我Add(a1, d2);這樣調(diào)用會怎么樣?大家看:

編譯器這個時候為難了,你到底想讓Tint呢?還是Tdouble呢?

那怎么辦,這個時候是不是就無法調(diào)用了。那我就想這樣調(diào)用怎么辦呢?

ok,也有。

此時有兩種處理方式:

1. 用戶自己來強(qiáng)制轉(zhuǎn)化

2. 使用顯式實例化

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

這兩個函數(shù)能不能同時存在?

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

// 專門處理int的加法函數(shù)
int Add(int left, int right)
{
	return left + right;
}
// 通用加法函數(shù)
template<class T>
T Add(T left, T right)
{
	return left + right;
}

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

也可以指定調(diào)用模板:

模板函數(shù)不允許自動類型轉(zhuǎn)換,但普通函數(shù)可以進(jìn)行自動類型轉(zhuǎn)換

所以當(dāng)一個匹配既沒有非模板函數(shù),也沒有函數(shù)模板可以匹配到的時候,會嘗試通過自動類型轉(zhuǎn)換調(diào)用到非模板函數(shù)(前提是可以轉(zhuǎn)換為非模板函數(shù)的參數(shù)類型)

3. 類模板

我們以前C語言要解決類型更換的問題用的是typedef,但是typedef不能解決全部的問題。

假設(shè)我們用以前的方法寫一個棧:

typedef int STDataType;
class Stack
{
public:
	Stack(int capacity = 0)
	{
		_a = new STDataType[capacity];
		_capacity = capacity;
		_top = 0;
	}
	~Stack()
	{
		cout << "~Stack()" << endl;
		delete[] _a;
		_capacity = 0;
		_top = 0;
	}
	void Push(STDataType x)
	{}
private:
	STDataType* _a;
	int _top;
	int _capacity;
};
int main()
{
	Stack st1; // int
	Stack st2; // double
	return 0;
}

C語言typedef的真正缺陷在于:如果我在一個程序里面定義了一個棧,那么不可能同時存在兩個存儲類型不同的棧。

C++由此提供了一個類模板。

3.1 類模板的定義格式

template<class T1, class T2, ..., class Tn>
class 類模板名
{
// 類內(nèi)成員定義
};

此時我們寫一個棧的模板:

template<class T>
class Stack
{
public:
	Stack(int capacity = 0)
	{
		_a = new T[capacity];
		_capacity = capacity;
		_top = 0;
	}
	~Stack()
	{
		cout << "~Stack()" << endl;
		delete[] _a;
		_capacity = 0;
		_top = 0;
	}
	void Push(const T& x)
	{}
private:
	T* _a;
	int _top;
	int _capacity;
};

類模板和函數(shù)模板不一樣:函數(shù)模板可以自動推導(dǎo)。類模板不能推導(dǎo),因為如果定義對象時構(gòu)造函數(shù)沒有傳參或者構(gòu)造函數(shù)沒有參數(shù),那就麻煩了,所以類模板得在調(diào)用的時候指定類型。

注意:Push的傳參不能傳值,因為存儲的類型不一樣,如果是自定義類型,還可能會考慮深拷貝的問題,代價就太大了,所以我們最好傳引用,引用實體不改變就加const。

3.2 類模板的實例化

類模板實例化與函數(shù)模板實例化不同,類模板實例化需要在類模板名字后跟<>,然后將實例化的類型放在<>中即可,類模板名字不是真正的類,而實例化的結(jié)果才是真正的類。

int main()
{
	//Stack是類名,Stack<int>才是類型
	Stack<int> st1; // int
	st1.Push(1);
	Stack<double> st2; // double
	st2.Push(2.2);
	return 0;
}

st1st2是兩個類,類型分別是Stack<int>Stack<double>。

4 模板分離編譯

4.1 模板的分離編譯

//聲明
template<class T>  
void Swap(T& left, T& right);
template<class T>
class Vector//Vector不是具體的類,是編譯器根據(jù)被實例化的類型生成具體類的模具,其實就是順序表
{
public:
	Vector(size_t capacity = 10);
private:
	T* _pData;
	size_t _size;
	size_t _capacity;
};
//定義
template<class T >
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}
template<class T>
Vector<T>::Vector(size_t capacity)
	: _pData(new T[capacity])
	, _size(0)
	, _capacity(capacity)
{}

模板分離編譯和普通的函數(shù)分離編譯還是不同的,最大的不同是:雖然聲明的時候給了模板參數(shù),但是定義的時候還要聲明一次,不然編譯器不知道T是哪來的。

但是這里還有一個問題:模板不支持聲明和定義分別放在xxx.h和xxx.cpp中!會出現(xiàn)鏈接錯誤!

來,我們來玩一下:

為什么模板分離編譯會鏈接不上?

ok,其實這里和模板的實例化有關(guān)系。

大家想一想編譯器把template.i處理成template.s,能干什么事情?

編譯器是不是應(yīng)該把類和函數(shù)編譯了放在符號表里面去?但是大家想一想,編譯器能不能處理?

ok,編譯器根本無從下手,其實templa.i編譯之后是空的,template.o和符號表也是空的,全都是空的。因為編譯器沒辦法知道模板參數(shù)T是啥!

大家再看調(diào)用的地方能不能編譯過,調(diào)用的地方?jīng)]啥毛病,能過。但是調(diào)用Swap和實例化對象調(diào)用構(gòu)造函數(shù)時會去call相應(yīng)函數(shù)的地址(正常是鏈接時拿修飾過的函數(shù)名去符號表里找這個地址)。但是符號表是空的呀,所以模板分離編譯,鏈接時找不到這些函數(shù)模板調(diào)用的地址。

4.2 解決方法

第一種方法:(推薦使用)

將聲明和定義放到一個文件 “xxx.hpp” (.h+.cpp合在一起這樣命名更規(guī)范)里面或者xxx.h其實也是可以的。

這樣頭文件展開的時候,就是聲明和定義一起在test.cpp中展開了,這樣test.cpp在編譯的時候直接就把模板實例化了,調(diào)用的時候也是直接call函數(shù)的地址了,不用鏈接的時候去找了。

第二種方法:模板定義的位置顯式實例化。這種方法不實用,不推薦使用。

到此這篇關(guān)于C++適用入門同學(xué)的模板講解的文章就介紹到這了,更多相關(guān)C++模板內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++直接cout指針名的含義?

    C++直接cout指針名的含義?

    今天小編就為大家分享一篇關(guān)于C++直接cout指針名的含義?,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • C++中fork函數(shù)的使用及原理

    C++中fork函數(shù)的使用及原理

    這篇文章主要介紹了C++中fork函數(shù)的使用及原理,在C++中,fork函數(shù)用于創(chuàng)建一個新的進(jìn)程稱為子進(jìn)程,該進(jìn)程與原始進(jìn)程幾乎完全相同,需要的朋友可以參考下
    2023-05-05
  • C語言動態(tài)開辟內(nèi)存詳解

    C語言動態(tài)開辟內(nèi)存詳解

    這篇文章主要為大家詳細(xì)介紹了C語言動態(tài)開辟內(nèi)存,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • QT設(shè)計秒表功能(跑步計時器)

    QT設(shè)計秒表功能(跑步計時器)

    這篇文章主要為大家詳細(xì)介紹了QT設(shè)計秒表功能,跑步計時器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 關(guān)于C++中數(shù)據(jù)16進(jìn)制輸出的方法

    關(guān)于C++中數(shù)據(jù)16進(jìn)制輸出的方法

    本文主要介紹了關(guān)于C++中數(shù)據(jù)16進(jìn)制輸出的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • C指針原理教程之語法樹及其實現(xiàn)

    C指針原理教程之語法樹及其實現(xiàn)

    本文給大家分享的是如何使用C語言的指針原來來實現(xiàn)語法樹,并給大家提供了詳細(xì)的實例代碼,希望大家能夠喜歡
    2019-02-02
  • 淺談C++的淺拷貝出現(xiàn)的錯誤

    淺談C++的淺拷貝出現(xiàn)的錯誤

    下面小編就為大家?guī)硪黄獪\談C++的淺拷貝出現(xiàn)的錯誤。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • 使用c語言輕松實現(xiàn)動態(tài)內(nèi)存管

    使用c語言輕松實現(xiàn)動態(tài)內(nèi)存管

    這篇文章主要介紹了使用c語言輕松實現(xiàn)動態(tài)內(nèi)存管,本文章內(nèi)容詳細(xì),具有很好的參考價值,希望對大家有所幫助,需要的朋友可以參考下
    2023-01-01
  • openCV中meanshift算法查找目標(biāo)的實現(xiàn)

    openCV中meanshift算法查找目標(biāo)的實現(xiàn)

    本文主要介紹了openCV中meanshift算法查找目標(biāo)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C語言猜兇手的代碼實現(xiàn)

    C語言猜兇手的代碼實現(xiàn)

    本文主要介紹了C語言猜兇手的代碼實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07

最新評論