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

C++模板全方位深入解讀

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

1.泛型編程

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

這點(diǎn)函數(shù)重載可以做到,比如一下Swap函數(shù)的重載,分別重載了倆種不同參數(shù)類型的Swap

void Swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}
void Swap(char& x, char& y)
{
	char tmp = x;
	x = y;
	y = tmp;
}

但是這也帶來了幾點(diǎn)不好的地方:

1.重載的函數(shù)僅僅是類型不同,代碼的復(fù)用率比較低,只要有新類型出現(xiàn),就需要增加對應(yīng)的函數(shù)

2.代碼的可維護(hù)性比較低,一個出錯可能所有的重載均出錯

那么有什么好的解決方法嗎?我們能否告訴編譯器一個模子,讓編譯器根據(jù)不同類型利用該模子自己去生成相應(yīng)的代碼呢?

當(dāng)然能,這就是泛型編程,即編寫與類型無關(guān)的通用代碼,這是代碼復(fù)用的一種手段。而模板是泛型編程的基礎(chǔ)。模板分為兩種,函數(shù)模板和類模板。

2.函數(shù)模板

概念

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

函數(shù)模板的格式

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

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

其中typename可以改成class(不能用struct)

例:

template <typename T>
void Swap(T& x, T& y)
{
	T tmp = x;
	x = y;
	y = tmp;
}

函數(shù)模板的原理

函數(shù)模板是一個藍(lán)圖,它本身并不是函數(shù),是編譯器用使用方式產(chǎn)生特定具體類型函數(shù)的模具。所以其實(shí)模板就是將本來應(yīng)該我們做的重復(fù)的事情交給了編譯器。

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

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

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

隱式實(shí)例化

讓編譯器自己推演函數(shù)參數(shù)的類型。

需要注意的是隱式實(shí)例化的參數(shù)一定要匹配,否則可能產(chǎn)生分歧導(dǎo)致編譯器無法識別。比如:

template<typename T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a1 = 10, b1 = 20;
	double a2 = 10.0, b2 = 20.0;
	Add(a1, b2);
	return 0;
}

編譯器報(bào)錯,該語句不能通過編譯,因?yàn)闊o法確定T是int還是double。

如何處理?有兩種方式:

1.強(qiáng)制類型轉(zhuǎn)換!但值得注意的是,強(qiáng)轉(zhuǎn)會產(chǎn)生臨時(shí)變量,臨時(shí)變量是具有常性的,需要const修飾一下!

2.使用顯式實(shí)例化

顯式實(shí)例化

在函數(shù)名后的< >中指定模板參數(shù)的實(shí)際類型。

template<typename T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a1 = 10, b1 = 20;
	double a2 = 10.0, b2 = 20.0;
	cout<<Add<int>(a1, b2)<<endl;
	return 0;
}

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

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

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

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

  • 如果有定義出來的函數(shù),且類型完全匹配調(diào)用時(shí)實(shí)參類型,則執(zhí)行定義出來的函數(shù).如果定義出來的函數(shù),不符合,則執(zhí)行模板推演.
  • 這部分沒啥難度,不再舉例說明,總的來說,對于函數(shù)調(diào)用的優(yōu)先級就是:完全匹配 >模板匹配 >轉(zhuǎn)換匹配。

3.類模板

(1) 類模板的定義格式

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

注意:

類模板中函數(shù)放在類外進(jìn)行定義時(shí),需要加模板參數(shù)列表;

template <typename T>
class Stack
{
public:
	Stack(int capacity = 4)
		:_a(new T[capacity])
		,_top(0)
		,_capacity(capacity)
	{}
	~Stack()
	{
		delete[] _a;
		_top = _capacity = 0;
	}
	void Push(T x);
private:
	T* _a;
	int _top;
	int _capacity;
};
// 注意:類模板中函數(shù)放在類外進(jìn)行定義時(shí),需要加模板參數(shù)列表
template <typename T>
void Stack<T>::Push(T x)
{
	if (_top == _capacity)
	{
		_capacity *= 2;
		T* tmp = (T*)realloc(_a, sizeof(int) * _capacity);
		if (tmp == nullptr)
		{
			cout << "realloc fail" << endl;
			exit(-1);
		}
		_a = tmp;
	}
	_a[_top++] = x;
}

對于普通類,類名就是類型;對于類模板,類名不是類型,類型是Class < T >

(2) 類模板的實(shí)例化

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

int main()
{
	// Stack只是類名,不是類型,Stack<int>才是類型
	Stack<int> s1;
	Stack<char> s2;
	return 0;
}

4.非類型模板參數(shù)

類型參數(shù):就是在模板的參數(shù)列表中在class后面加上參數(shù)的類型名稱。

非類型參數(shù):就是用一個常量作為類(函數(shù))模板的一個參數(shù),在類(函數(shù))模板中可將該參數(shù)當(dāng)成常量來使用。

注意兩點(diǎn):

1.浮點(diǎn)數(shù)、類對象以及字符串是不允許作為非類型模板參數(shù)的。

2.非類型的模板參數(shù)必須在編譯期就能確認(rèn)結(jié)果。

template<class T =int, size_t N = 10>
class array
	{
		 private:
	 	 T _array[N];
		 size_t _size;
	 }

5.模板特化

(1)函數(shù)模板的特化

當(dāng)針對某一情景或者某一類型,函數(shù)模板無法滿足要求,模板需要有特殊的處理,這個時(shí)候就需要用到模板的特化。

比如咱們要比較兩個字符串是否相同:

template<class T>
bool IsEqual(T str1, T str2)
{
	return str1 == str2;
}
int main()
{
	char str1[] = "hello";
	char str2[] = "hello";
	if (IsEqual(str1, str2))
		cout << "true";
	else
		cout << "false";
}

上述代碼輸出false, 不滿足咱們的要求, 因?yàn)檎{(diào)用函數(shù)IsEqual()時(shí)傳遞過去的是兩個char*類型,他們兩個比較的不是字符串的內(nèi)容,而是指針的地址,所以返回false。

此時(shí)模板特化派上用場了:如果要比較char*, 可以用strcmp來對這個情況進(jìn)行特殊處理

template<>
bool IsEqual<char*>(char* str1, char* str2)
{
	return strcmp(str1, str2) == 0;
}

此時(shí)就返回true, 符合預(yù)期了。

函數(shù)模板的特化步驟:

  • 必須要先有一個基礎(chǔ)的函數(shù)模板
  • 關(guān)鍵字template后面接一對空的尖括號<>
  • 函數(shù)名后跟一對尖括號,尖括號中指定需要特化的類型
  • 函數(shù)形參表: 必須要和模板函數(shù)的基礎(chǔ)參數(shù)類型完全相同

(2)類模板的特化

類也是同理,如果需要有特殊情景也需要特化處理

以如下類舉例(后邊全特化、偏特化都針對它):

template<class T1, class T2>
class test
{
public:
	test()
	{
		cout << "test<T1, T2>" << endl;
	}
private:
	T1 _x;
	T2 _y;
};

全特化

全特化即是將模板參數(shù)列表中所有的參數(shù)都確定化。

例如:

這里對test<int,double>版本特化

template<>
class test<int, double>
{
public:
	test()
	{
		cout << "test<int, double>" << endl;
	}
private:
	int _x;
	double _y;
};
int main()
{
	test<double, double> t1;
	test<int, double> t2;
}

偏特化

偏特化即是任何針對模版參數(shù)進(jìn)一步進(jìn)行條件限制設(shè)計(jì)的特化版本

偏特化有兩種表現(xiàn)方式,一種是部分參數(shù)特化,一種是參數(shù)修飾特化

部分參數(shù)特化

這里對第二個參數(shù)特化,只要第二個參數(shù)是double就會調(diào)用對應(yīng)特化版本

template<class T1>
class test<T1, double>
{
public:
	test()
	{
		cout << "test<T1, double>" << endl;
	}
private:
	T1 _x;
	double _y;
};
int main()
{
	test<double, double> t1;
	test<int, double> t2;
}

參數(shù)修飾特化

比如用指針或者引用來修飾類型,也可以進(jìn)行特化

template<class T1, class T2>
class test<T1*, T2*>
{
public:
	test()
	{
		cout << "test<T1*, T2*>" << endl;
	}
private:
	T1* _x;
	T2* _y;
};
int main()
{
	test<int*, double*> t;
}

6.模板的分離編譯

對于一個代碼量比較多的項(xiàng)目,通常都會采用聲明與定義分離的方法,比如在頭文件進(jìn)行聲明,在源文件完成代碼的實(shí)現(xiàn),最后通過鏈接的方法鏈接成單一的可執(zhí)行文件。但是C++的編譯器卻不支持模板的分離編譯,一旦進(jìn)行分離編譯,就會出現(xiàn)鏈接錯誤。

問題分析

//頭文件a.h
template<class T>
bool IsEqual(const T& str1, const T& str2);
-------------
//源文件a.cpp
template<class T>
bool IsEqual(const T& str1, const T& str2)
{
	return str1 == str2;
}
--------------
//test.c
#include<iostream>
#include"a.h"
using namespace std;
int main()
{
	cout << IsEqual(3, 5);
	cout << IsEqual('a', 'b');
}

這里看上去是沒有問題的,但是涉及到了模板的實(shí)例化規(guī)則。

當(dāng)主函數(shù)調(diào)用這個函數(shù)的時(shí)候他就會去頭文件中找到函數(shù)的聲明,再通過聲明找到a.h中的實(shí)現(xiàn)。

但是對于模板卻并不會這樣,因?yàn)樯弦徽抡f過,模板的實(shí)例化只會在其第一次使用的時(shí)候才會進(jìn)行,例如這里IsEqual(3, 5),他就會去頭文件中尋找,但是頭文件中只有聲明,沒有定義,無法將其實(shí)例化。他又想通過找到a.cpp中的函數(shù)定義來進(jìn)行實(shí)例化,但是遺憾的是,a.cpp中只有IsEqual(const T& str1, const T& str2)的定義,沒有IsEqual(const int & str1, const int T& str2),因?yàn)樵赼.cpp中并沒有使用到該類型的實(shí)例,所以自然也不會為其實(shí)例化出來,這時(shí)test.cpp中就根本無法找到這個函數(shù)的實(shí)現(xiàn),就導(dǎo)致了鏈接失敗。

解決方法:

這個問題其實(shí)沒有什么完美的解決方法

  • 將聲明和定義放到同一個頭文件中。
  • 類模板顯式實(shí)例化。

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

相關(guān)文章

  • C++實(shí)現(xiàn)Dijkstra(迪杰斯特拉)算法

    C++實(shí)現(xiàn)Dijkstra(迪杰斯特拉)算法

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)Dijkstra(迪杰斯特拉)算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • C++動態(tài)規(guī)劃實(shí)現(xiàn)查找最長公共子序列

    C++動態(tài)規(guī)劃實(shí)現(xiàn)查找最長公共子序列

    這篇文章主要介紹了C++動態(tài)規(guī)劃最長公共子序列,在動態(tài)規(guī)劃中,你要將某個指標(biāo)最大化。在這個例子中,你要找出最長公共子序列
    2022-06-06
  • 詳解C語言中Char型指針數(shù)組與字符數(shù)組的區(qū)別

    詳解C語言中Char型指針數(shù)組與字符數(shù)組的區(qū)別

    這篇文章主要介紹了詳解C語言中Char型指針數(shù)組與字符數(shù)組的區(qū)別的相關(guān)資料,希望通過本文能幫助到大家掌握理解這部分內(nèi)容,需要的朋友可以參考下
    2017-10-10
  • C++實(shí)現(xiàn)Linux下彈出U盤的方法

    C++實(shí)現(xiàn)Linux下彈出U盤的方法

    這篇文章主要介紹了C++實(shí)現(xiàn)Linux下彈出U盤的方法,實(shí)例分析了C++在Linux平臺上進(jìn)行IO操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • C++進(jìn)程共享數(shù)據(jù)封裝成類實(shí)例

    C++進(jìn)程共享數(shù)據(jù)封裝成類實(shí)例

    這篇文章主要介紹了C++進(jìn)程共享數(shù)據(jù)封裝成類的方法,以實(shí)例形式講述了其封裝代碼與具體用法,具有一定的實(shí)用價(jià)值,需要的朋友可以參考下
    2014-10-10
  • C語言實(shí)現(xiàn)三子棋簡單小游戲

    C語言實(shí)現(xiàn)三子棋簡單小游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)三子棋簡單小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C語言中的指針 初階

    C語言中的指針 初階

    這篇文章主要介紹的是關(guān)于初級階段學(xué)習(xí)C語言中指針的一些內(nèi)容,那就是指針是什么?簡單的說,就是通過它能找到以它為地址的內(nèi)存單元。下面文章我們就來詳細(xì)介紹該內(nèi)容,需要的朋友可以參考一下
    2021-10-10
  • C語言編程C++柔性數(shù)組結(jié)構(gòu)示例講解

    C語言編程C++柔性數(shù)組結(jié)構(gòu)示例講解

    這篇文章主要介紹了C語言編程系列中的柔性數(shù)組,文中含有詳細(xì)的示例代碼講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-09-09
  • C語言各類操作符全面講解

    C語言各類操作符全面講解

    C?語言提供了豐富的操作符,有:算術(shù)操作符,移位操作符,位操作符,賦值操作符,單目操作符,關(guān)系操作符,邏輯操作符,條件操作符等。接下了讓我們詳細(xì)了解掌握它
    2022-05-05
  • C++11?成員函數(shù)作為回調(diào)函數(shù)的使用方式

    C++11?成員函數(shù)作為回調(diào)函數(shù)的使用方式

    這篇文章主要介紹了C++11?成員函數(shù)作為回調(diào)函數(shù)的使用方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評論

惠州市| 乌兰察布市| 瓦房店市| 沿河| 乐山市| 永康市| 盐城市| 禹城市| 布尔津县| 阜南县| 三门峡市| 刚察县| 饶河县| 昌乐县| 嵊州市| 邵武市| 诸城市| 通榆县| 白水县| 边坝县| 汉中市| 广南县| 越西县| 安龙县| 灌云县| 会泽县| 博白县| 邻水| 县级市| 铜梁县| 依兰县| 尚义县| 崇左市| 南康市| 霍州市| 务川| 松阳县| 翁牛特旗| 临漳县| 宁国市| 阳江市|