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

C++印刷模板使用方法詳解

 更新時(shí)間:2022年11月10日 11:39:32   作者:The s.k.y.  
模板是C++支持參數(shù)化多態(tài)的工具,使用模板可以使用戶(hù)為類(lèi)或者函數(shù)聲明一種一般模式,使得類(lèi)中的某些數(shù)據(jù)成員或者成員函數(shù)的參數(shù)、返回值取得任意類(lèi)型

在了解string之前,我們需要了解模板等等的一些鋪墊知識(shí),讓我們開(kāi)始吧!

一、泛型編程

泛型編程是什么意思呢?我們通過(guò)下面的例子來(lái)具體了解:

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;
}
int main()
{
	int a = 1, b = 2;
	Swap(a, b);	
    double c=1.33,d=2.33;
    Swap(a,b)
}

就拿交換函數(shù)來(lái)說(shuō),當(dāng)我們交換不同類(lèi)型的變量的值,那就需要不停的寫(xiě)交換函數(shù)的重載,這樣代碼復(fù)用率就較低,那我們能不能創(chuàng)造一個(gè)模板呢??

一個(gè)Swap的模板,但是我可以用不同的類(lèi)型去實(shí)現(xiàn)這個(gè)模板,繼而試用它。

如果在 C++ 中,也能夠存在這樣一個(gè) 模具 ,通過(guò)給這個(gè)模具中 填充不同材料 ( 類(lèi)型 ) ,來(lái) 獲得不同材料的鑄件 ( 即生成具體類(lèi)型的代碼)。 泛型編程:編寫(xiě)與類(lèi)型無(wú)關(guān)的通用代碼,是代碼復(fù)用的一種手段。模板是泛型編程的基礎(chǔ)。

二、模板(初階)

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

1.函數(shù)模板

1.單參數(shù)類(lèi)型

函數(shù)模板代表了一個(gè)函數(shù)家族,該函數(shù)模板與類(lèi)型無(wú)關(guān),在使用時(shí)被參數(shù)化,根據(jù)實(shí)參類(lèi)型產(chǎn)生函數(shù)的特定 類(lèi)型版本。 就拿Swap來(lái)說(shuō): typename 是 用來(lái)定義模板參數(shù) 關(guān)鍵字,T是類(lèi)型(也可以用class,(class T))

template<typename T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}
int main()
{
	    int a = 1, b = 2;
	    Swap(a, b);
        int x = 1, y = 2;
		Swap(x, y);
		double m = 1.1, n = 2.2;
		Swap(m, n);
		char p = 'a', q = 'b';
		Swap(p, q);
        Swap(m,a);//不同類(lèi)型
}

那么,具體是怎樣實(shí)現(xiàn)的呢?

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

編譯器通過(guò)類(lèi)型推演,將函數(shù)模板進(jìn)行實(shí)例化,對(duì)應(yīng)的T就會(huì)替換成具體的類(lèi)型,模板實(shí)例化是用幾個(gè)實(shí)例化幾個(gè),不是所有不同類(lèi)型都提前模板實(shí)例化。

1.當(dāng)變量類(lèi)型相同,但是變量不同,調(diào)用Swap();模板實(shí)例化只會(huì)實(shí)例化一個(gè),因?yàn)殡m然變量不同,但類(lèi)型相同,模板實(shí)例化就是將T換成具體的類(lèi)型。

2.當(dāng)Swap(m,a),變量是不同類(lèi)型時(shí),會(huì)發(fā)生什么??

因?yàn)樵谕蒲輛oid Swap(T& left, T& right);時(shí),T的類(lèi)型不明確,就會(huì)發(fā)生錯(cuò)誤(推演報(bào)錯(cuò)),直接報(bào)錯(cuò)

但如果不用模板,我們自己這樣:

void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}
int main()
{
  int a=2;
  double b=2.22;
  Swap(a,b);
}

可能有人就會(huì)想:在Swap(a,b)中,會(huì)不會(huì)a和b發(fā)生飲食類(lèi)型轉(zhuǎn)化呢?較小的類(lèi)型轉(zhuǎn)化成較大的類(lèi)型。

當(dāng)然不會(huì):隱式類(lèi)型轉(zhuǎn)化只有在 賦值:b=3;(產(chǎn)生臨時(shí)變量);函數(shù)傳參的時(shí)候(產(chǎn)生臨時(shí)變量),才會(huì)發(fā)生隱式類(lèi)型轉(zhuǎn)化。

函數(shù)形參是引用,當(dāng)類(lèi)型是引用時(shí),我們就要小心:是否會(huì)發(fā)生權(quán)限放大?當(dāng)b傳值時(shí),中間的臨時(shí)變量具有常性(只讀),而形參是可讀可寫(xiě),權(quán)限就會(huì)放大,也是不可以通過(guò)的,除非加了const,但是加了const就無(wú)法交換了,所以這樣還是行不通的!

自動(dòng)推演實(shí)例化和顯式實(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.1, d2 = 20.2;
	// 自動(dòng)推演實(shí)例化
	cout << Add(a1, a2) << endl;
	cout << Add(d1, d2) << endl;
	cout << Add((double)a1, d2) << endl; //強(qiáng)制類(lèi)型轉(zhuǎn)化也是產(chǎn)生臨時(shí)變量,不是改變a1
	cout << Add(a1, (int)d2) << endl;
	// 顯示實(shí)例化
	cout << Add<double>(a1, d2) << endl;//隱式類(lèi)型轉(zhuǎn)化
	cout << Add<int>(a1, d2) << endl;
	return 0;
}

在自動(dòng)推演實(shí)例化中,必須強(qiáng)轉(zhuǎn),不然還是和之前問(wèn)題一樣,該語(yǔ)句不能通過(guò)編譯,因?yàn)樵诰幾g期間,當(dāng)編譯器看到該實(shí)例化時(shí),需要推演其實(shí)參類(lèi)型通過(guò)實(shí)參a1將T推演為int,通過(guò)實(shí)參d1將T推演為double類(lèi)型,但模板參數(shù)列表中只有一個(gè)T,編譯器無(wú)法確定此處到底該將T確定為int 或者 double類(lèi)型而報(bào)錯(cuò)。 (推演報(bào)錯(cuò))

不強(qiáng)轉(zhuǎn)情況:顯示實(shí)例化,:在函數(shù)名后的<>中指定模板參數(shù)的實(shí)際類(lèi)型(我讓你怎么來(lái)你就怎么來(lái)?。?/p>

在函數(shù)名后加入了指定模板參數(shù)后,就會(huì)在實(shí)例化時(shí),T直接是指定的類(lèi)型,這樣就會(huì)發(fā)生隱式類(lèi)型轉(zhuǎn)換。

注意:在模板中,編譯器一般不會(huì)進(jìn)行類(lèi)型轉(zhuǎn)換操作,因?yàn)橐坏┺D(zhuǎn)化出問(wèn)題,編譯器就需要背黑鍋 Add(a1, d1); 此時(shí)有兩種處理方式:1. 用戶(hù)自己來(lái)強(qiáng)制轉(zhuǎn)化 2. 使用顯式實(shí)例化

2.多參數(shù)類(lèi)型

template<typename T1,typename T2),T1,T2為不同類(lèi)型,當(dāng)然參數(shù)個(gè)數(shù)大于等于2

template<class t1,class t2>
t1 Add(const t1& left, const t2& right)
{
	return left + right;
}
int main()
{
	int a = 1, b = 2;
	double m = 2.22, n = 3.33;
	cout << Add(a, b) << endl;
	cout << Add(m, n) << endl;
	cout << Add(a, m) << endl;
	cout << Add(n, b) << endl;
}

此時(shí),當(dāng)Add(不同類(lèi)型時(shí)),就不會(huì)發(fā)生推演錯(cuò)誤,你是什么類(lèi)型就會(huì)推演成什么模板函數(shù)。

3.模板函數(shù)和自定義函數(shù)

當(dāng)模板函數(shù)和自己實(shí)現(xiàn)的函數(shù)是否可以同時(shí)存在時(shí)?

//專(zhuān)門(mén)處理int的加法函數(shù)
int Add(int left, int right) 
{
	return left + right;
}
// 通用加法函數(shù)
template<class T>
T Add(T left, T right) 
{
	return left + right;
}
int main()
{
	int a = 1, b = 2;
	Add(a, b);
	Add<int>(a, b);
	return 0;
}

當(dāng)自己寫(xiě)的函數(shù)和模板函數(shù)同時(shí)存在時(shí),二者不會(huì)沖突,在之前我們講過(guò)他們的函數(shù)名修飾規(guī)則是不同的。

同時(shí)存在,且調(diào)用時(shí),首先會(huì)調(diào)用自己寫(xiě)的函數(shù)。因?yàn)槟0搴瘮?shù)相當(dāng)于一個(gè)半成品,他需要推演實(shí)例化才會(huì)生成具體的函數(shù),所以當(dāng)然先使用自己實(shí)現(xiàn)的。

如果一定要使用模板函數(shù)的話,就需要顯示實(shí)例化:Add<int>(a,b);

這就叫泛型編程,與具體的類(lèi)型無(wú)關(guān)!

2.類(lèi)模板

類(lèi)模板與函數(shù)模板不同的是:類(lèi)模板統(tǒng)一顯式實(shí)例化,不需要推演,或者說(shuō)沒(méi)有推演的時(shí)機(jī),而函數(shù)模板實(shí)參傳遞形參時(shí),就會(huì)發(fā)生推演實(shí)例化。

格式:

template<typename T>
class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = (T*)malloc(sizeof(T)*capacity);
		if (_a == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		_top = 0;
		_capacity = capacity;
	}
	 ......
private:
	T* _a;
	int _top;
	int _capacity;
};
int main()
{
	// 顯示實(shí)例化
	Stack<double> st1; // double
	st1.Push(1.1);
	Stack<int> st2; // int
	st2.Push(1);
	// s1,s2是同一個(gè)類(lèi)模板實(shí)例化出來(lái)的,但是模板參數(shù)不同,他們就是不同類(lèi)型
	return 0;
}

可能有人會(huì)問(wèn):s1=s2; 會(huì)不會(huì)發(fā)生隱式類(lèi)型轉(zhuǎn)換呢?當(dāng)然不會(huì),隱式類(lèi)型轉(zhuǎn)換只有在類(lèi)型相近才會(huì)發(fā)生。

接下來(lái)創(chuàng)建一個(gè)數(shù)組類(lèi)模板:

namespace mj
{
	template<class T>
	class array
	{
	public:
		inline T& operator[](size_t i)  //這里引用做返回值的目的是除了減少拷貝構(gòu)造,還有可以修改返回值,直接可以修改數(shù)組里的值
		{
			assert(i < N);  //嚴(yán)格控制越界訪問(wèn)的情況
			return _a[i];
		}
	private:
		T _a[N];
	};
}
int main()
{
	mj::array<int> a1;
	for (size_t i = 0; i < N; ++i)
	{
		//相當(dāng)于: a1.operator[](i)= i;
		a1[i] = i;
	}
	for (size_t i = 0; i < N; ++i)
	{
		// a1.operator[](i)
		cout << a1[i] << " ";
	}
	cout << endl;
	for (size_t i = 0; i < N; ++i)
	{
		a1[i]++;
	}
	for (size_t i = 0; i < N; ++i)
	{
		cout << a1[i] << " ";
	}
	cout << endl;
	return 0;
}

我們可以發(fā)現(xiàn),類(lèi)對(duì)象居然也可以使用數(shù)組那一套了??當(dāng)然是取決于運(yùn)算符重載。

他與普通數(shù)組最大的區(qū)別是:

1. 普通數(shù)組對(duì)于數(shù)組越界的這種情況,只能隨機(jī)的抽查!而我們自己實(shí)現(xiàn)的類(lèi)模板可以嚴(yán)格的控制越界訪問(wèn)這種情況!別說(shuō)越界修改,越界訪問(wèn)都不行!

2.效率上因?yàn)閇]是運(yùn)算符重載,使用就會(huì)調(diào)用函數(shù)開(kāi)辟棧幀,但是若定義到類(lèi)中,并且加inline,就對(duì)于效率來(lái)說(shuō),那真是完美!

3.模板不支持分離編譯

我們?cè)趯?shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)的時(shí)候,是不是會(huì)經(jīng)常去分幾個(gè)文件去實(shí)現(xiàn)不同模塊的功能?

(個(gè)人習(xí)慣).h文件中,我們寫(xiě)聲明;.cpp文件中,我們寫(xiě)定義;test.cpp中,我們測(cè)試使用

但今天學(xué)習(xí)的模板就不能這么做了??!具體不能怎么做,我們上代碼:

如果這樣寫(xiě)的話,他就會(huì)報(bào)鏈接錯(cuò)誤(就是在使用時(shí)找不到定義)

我們知道,在預(yù)處理階段,就會(huì)將.h頭文件展開(kāi),test.cpp中只有聲明,在調(diào)用函數(shù)時(shí),就會(huì)去找他的地址(call stack()),那么在編譯的時(shí)候,編譯器允許只有聲明沒(méi)有函數(shù),相當(dāng)于你可以先給他一個(gè)承諾,兌不兌現(xiàn)后面再說(shuō)。

但在鏈接的時(shí)候,test.cpp中,卻不能找到它的地址,這是為什么??這就是模板和其他的區(qū)別!

鏈接錯(cuò)誤原因:

.cpp中的定義,不是實(shí)例化模板,他只是一個(gè)模板,沒(méi)有任何實(shí)例化成任何類(lèi)型。所以你在使用類(lèi)模板的時(shí)候,壓根就找不到它的定義,當(dāng)然也找不到地址了,這不就鏈接錯(cuò)誤了嗎?

看上圖:stack<int> st; 顯示實(shí)例化,但是.h中只有聲明,test.cpp用的地方實(shí)例化了,但是定義的地方stack.cpp卻沒(méi)有實(shí)例化,只是一個(gè)模板。

用的地方在實(shí)例化,但是有聲明,沒(méi)有定義;

定義的地方?jīng)]有實(shí)例化。

解決方法:

那轉(zhuǎn)來(lái)轉(zhuǎn)去就是一個(gè)問(wèn)題:stack.cpp中定義沒(méi)有實(shí)例化?。?/p>

辦法一:

你沒(méi)有實(shí)例化,我給你補(bǔ)上:在定義后面加一個(gè)實(shí)例化

template<class T>
Stack<T>::Stack(int capacity = 4)
{
	cout << "Stack(int capacity = )" << capacity << endl;
	_a = (T*)malloc(sizeof(T)*capacity);
	if (_a == nullptr)
	{
		perror("malloc fail");
		exit(-1);
	}
	_top = 0;
	_capacity = capacity;
	template
	class Stack<int>;

但是就會(huì)有另一個(gè)問(wèn)題,我如果使用的時(shí)候,創(chuàng)建不同類(lèi)型,那模板實(shí)例化就要有不同類(lèi)型,那就要一直補(bǔ)實(shí)例化,總不肯用一個(gè)補(bǔ)一個(gè)吧。

方法二:

那就是模板的編譯不分離:(不要將定義和聲明一個(gè)到.cpp,一個(gè)到.h)

當(dāng)放在一個(gè)文件中時(shí),在編譯時(shí),.h 文件展開(kāi)后,定義和聲明都在test.cpp中,那直接就會(huì)完成模板實(shí)例化,就有了函數(shù)地址,不需要再去鏈接了。

鏈接:只有聲明沒(méi)有定義才會(huì)到處去找定義。

那有人就會(huì)問(wèn),加inline可以嗎?

inline當(dāng)然不可以,加了inline后,直接不產(chǎn)生符號(hào)表,還存在什么地址嗎?

直接放類(lèi)中也不行,當(dāng)數(shù)據(jù)量大的時(shí)候,都擠到一推,代碼閱讀性很差,會(huì)傻傻搞不清!

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

相關(guān)文章

  • C語(yǔ)言結(jié)構(gòu)體內(nèi)存的對(duì)齊知識(shí)詳解

    C語(yǔ)言結(jié)構(gòu)體內(nèi)存的對(duì)齊知識(shí)詳解

    這篇文章主要介紹了C語(yǔ)言結(jié)構(gòu)體內(nèi)存的對(duì)齊的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • C++模版函數(shù)詳解

    C++模版函數(shù)詳解

    C++中的模版總體可以分為兩大類(lèi):模版函數(shù)、模版類(lèi)。本篇文章先寫(xiě)模版函數(shù),需要的朋友可以參考下
    2017-02-02
  • OpenCV實(shí)現(xiàn)Sobel邊緣檢測(cè)的示例

    OpenCV實(shí)現(xiàn)Sobel邊緣檢測(cè)的示例

    本文主要介紹了OpenCV實(shí)現(xiàn)Sobel邊緣檢測(cè)的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • QT5連接MySQL實(shí)現(xiàn)增刪改查

    QT5連接MySQL實(shí)現(xiàn)增刪改查

    這篇文章主要為大家詳細(xì)介紹了QT5如何連接MySQL實(shí)現(xiàn)增刪改查功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的可以了解一下
    2022-12-12
  • 詳解C語(yǔ)言中telldir()函數(shù)和seekdir()函數(shù)的用法

    詳解C語(yǔ)言中telldir()函數(shù)和seekdir()函數(shù)的用法

    這篇文章主要介紹了詳解C語(yǔ)言中telldir()函數(shù)和seekdir()函數(shù)的用法,是C語(yǔ)言入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • 求素?cái)?shù),用vector存儲(chǔ)的實(shí)現(xiàn)方法

    求素?cái)?shù),用vector存儲(chǔ)的實(shí)現(xiàn)方法

    本篇文章是對(duì)求素?cái)?shù),用vector存儲(chǔ)的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 詳解如何在C/C++中測(cè)量一個(gè)函數(shù)或功能的運(yùn)行時(shí)間

    詳解如何在C/C++中測(cè)量一個(gè)函數(shù)或功能的運(yùn)行時(shí)間

    本文算是一個(gè)比較完整的關(guān)于在 C/C++ 中測(cè)量一個(gè)函數(shù)或者功能的總結(jié),最后會(huì)演示三種方法的對(duì)比,文章通過(guò)代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • C語(yǔ)言折半查找法介紹及使用示例

    C語(yǔ)言折半查找法介紹及使用示例

    折半查找法也叫做?分查找,顧名思義就是把數(shù)據(jù)分成兩半,再判斷所查找的key在哪?半中,再重復(fù)上述步驟知道找到?標(biāo)key,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言折半查找法的相關(guān)資料,需要的朋友可以參考下
    2022-08-08
  • C++20中的span容器及用法小結(jié)

    C++20中的span容器及用法小結(jié)

    std::span 是一個(gè)非常實(shí)用的工具,可以方便地對(duì)數(shù)據(jù)進(jìn)行訪問(wèn)和處理,同時(shí)也可以提高代碼的可讀性、可維護(hù)性和安全性,這篇文章主要介紹了C++20中的span容器,需要的朋友可以參考下
    2023-03-03
  • 探究C++中指針與數(shù)組運(yùn)算符優(yōu)先級(jí)

    探究C++中指針與數(shù)組運(yùn)算符優(yōu)先級(jí)

    C++中與指針和數(shù)組相關(guān)的運(yùn)算符優(yōu)先級(jí),通過(guò)實(shí)際代碼示例解釋了運(yùn)算符的左結(jié)合與右結(jié)合方式,以及如何使用圓括號(hào)()來(lái)改變默認(rèn)的結(jié)合順序,文章還提供了一個(gè)優(yōu)先級(jí)表,列出了運(yùn)算符的優(yōu)先級(jí)和結(jié)合性,幫助讀者更好地理解復(fù)雜表達(dá)式中運(yùn)算符的調(diào)用順序
    2024-10-10

最新評(píng)論

姚安县| 改则县| 红河县| 南澳县| 宁化县| 安泽县| 固阳县| 遂平县| 鹤庆县| 察哈| 汕头市| 靖远县| 寿宁县| 修文县| 且末县| 娱乐| 临江市| 孙吴县| 邓州市| 石台县| 武川县| 沧州市| 杂多县| 肃北| 辽中县| 土默特右旗| 巫山县| 兴海县| 玉田县| 普兰县| 邹平县| 永兴县| 孝义市| 宾川县| 马鞍山市| 上栗县| 庆云县| 车致| 定安县| 靖江市| 彩票|