日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ Primer 学习笔记_75_模板与泛型编程 --模板定义

發布時間:2025/4/5 c/c++ 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ Primer 学习笔记_75_模板与泛型编程 --模板定义 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

模板與泛型編程

--模板定義



引言:

所謂泛型程序就是以獨立于不論什么特定類型的方式編寫代碼。使用泛型程序時,我們須要提供詳細程序實例所操作的類型或值。

模板是泛型編程的基礎。使用模板時能夠無須了解模板的定義。

泛型編程與面向對象編程一樣,都依賴于某種形式的多態性。面向對象編程中的多態性在執行時應用于存在繼承關系的類。我們能夠編寫使用這些類的代碼,忽略基類與派生類之間類型上的差異。僅僅要使用基類的引用或指針,基類類型或派生類類型的對象就能夠使用同樣的代碼。

在泛型編程中,我們所編寫的函數能夠多態地用于跨越編譯時不相關的類型。一個類或一個函數能夠用來操縱多種類型對象。標準庫中的容器、迭代器和算法是非常好的泛型編程的樣例。標準庫用獨立于類型的方式定義每一個容器、迭代器和算法,因此差點兒能夠在隨意類型上使用標準庫的類和函數。

C++,模板是泛型編程的基礎。模板是創建類或函數的藍圖或公式。



編寫重載函數:

int compare(const string &v1,const string &v2) {if (v1 < v2){return -1;}else if (v1 > v2){return 1;}return 0; }int compare(const double &v1,const double &v2) {if (v1 < v2){return -1;}else if (v1 > v2){return 1;}return 0; }

這些函數差點兒同樣,它們之間唯一的差別是形參的類型,每一個函數的函數體是同樣的。

每一個要比較的類型都須要反復函數的函數體,不僅麻煩并且easy出錯。更重要的是,須要事先知道空間可能會比較哪些類型。假設希望將函數用于未知類型,這樣的策略就不起作用了。



一、定義函數模板

我們能夠不用為每一個類型定義一個新函數,而是定義一個函數模板。函數模板是一個獨立于類型的函數,能夠作為一種方式,產生函數的特定類型版本號。

template<typename T> int compare(const T &v1,const T &v2) {if (v1 < v2){return -1;}else if (v1 > v2){return 1;}return 0; }

模板定義以keywordtemplate開始,后接模板形參表,模板形參表是用尖括號括住的一個或多個模板形參的列表,形參之間以逗號分隔。并且模板形參表不能為空。



1、模板形參表

模板形參表類似于函數形參表,表示能夠在類或函數的定義中使用的類型或值。比如,compare 函數聲明一個名為T的類型形參。在compare內部,能夠使用名字T引用一個類型,T表示哪個實際類型由編譯器依據所用的函數而確定。

模板形參能夠是表示類型的類型形參,或者是表示常量表達式的非類型形參。類型形參跟在keywordclasstypename之后定義。



2、使用函數模板

使用函數模板時,編譯器會判斷哪個(或哪些)模板實參綁定到模板形參。一旦編譯器確定了實際的模板實參,就稱它實例化了函數模板的一個實例。

推導出實際模板實參后,編譯器使用實參取代相應的模板形參產生編譯該版本號的函數。

int main () {// 綁定到compare(const int&, const int&)cout << compare(1, 0) << endl;// 綁定到compare(const string&, const string&)string s1 = "hi", s2 = "world";cout << compare(s1, s2) << endl;return 0; }

3、inline函數模板

inline說明符放在模板形參表之后、返回類型之前,不能放在keywordtemplate之前。

template<typename T> inline int compare(const T &v1,const T &v2); //OKinline template<typename T> int compare(const T &v1,const T &v2); //Error
//P528 習題16.1 template<typename T> inline T abs(T val) {return val > 0 ? val : -val; }int main () {cout << abs(-1) << endl;cout << abs(-0.98) << endl;cout << abs(short(3.4)) << endl;return 0; }
//習題16.2 template<typename T> ostream &write(ostream &os,T val) {return os << val << endl; }int main() {write(cout,1);write(cout,12.3);write(cout,"Hello World");ofstream outFile("output");write(outFile,"Hello");write(outFile,123);string temp;ostringstream strStream(temp);write(strStream,"Hello_World");cout << strStream.str() << endl; }

二、定義類模板

為了舉例說明類模板,我們將為標準庫queue類實現一個自己的版本號。

我們自己定義的Queue類必須能夠支持不同類型的對象,所以將它定義為類模板。Queue所能支持的操作:

1push:在隊尾加入一項

2pop:從隊頭刪除一項

3front:返回隊頭的引用

4empty:指出隊列是否為空

template<typename Type> class Queue { public:Type &front();const Type &front() const;void push(const Type &);void pop();bool empty() const;private://... };

類模板也是模板,因此必須以keywordtemplate開頭,后接模板形參表。

除了模板形參表外,類模板的定義看起來與隨意其它類類似。在類和類成員的定義中,能夠使用模板形參作為類型占位符,在使用類時再提供那些類型或值。



使用類模板

與調用函數模板形成對照,使用類模板時,必須為模板形參顯式指定實參

Queue<int> qi;Queue< vector<double> > qc;Queue<string> qs;

編譯器使用實參實例化這個類的特定類型版本號。實質上,編譯器用用戶提供的實際特定類型取代Type,又一次編寫Queue類。在這個樣例中,編譯器將實例化三個Queue:第一個用int取代 Type,第二個用vector<double>取代 Type,第三個用string取代 Type。

//P529 習題16.5 template<typename T> T getBigger(const T &val1,const T &val2) {return val1 > val2 ? val1 : val2; }
//習題16.6 template<typename Type> class List { public:List();void push_back(const Type &);void push_front(const Type &);std::size_t size() const;void insert(Type *ptr,const Type &val);bool empty();private://... };

三、模板形參

像函數形參一樣,為模板形參選擇的名字沒有本質含義:

template<typename Glorp> int compare(const Glorp &v1,const Glorp &v2) {if (v1 < v2){return -1;}else if (v1 > v2){return 1;}return 0; }

該代碼與前面定義的compare模板一樣。

能夠給模板形參授予的唯一含義是差別是類型形參還是非類型形參。假設是類型形參,我們就知道該形參表示未知類型,假設是非類型形參,我們就知道它是一個未知值。

假設希望使用模板形參所表示的類型或值,能夠使用與相應模板形參同樣的名字。比如,compare函數中全部的Glorp引用將在該函數被實例化時確定為同一類型。



1、模板形參作用域

模板形參的名字能夠在聲明為模板形參之后直到模板聲明定義的末尾處使用。

模板形參遵循常規名字屏蔽規則:

typedef double T; template <class T> T calc(const T &a,const T &b) {//此處T為template形參表中的T,全局名字被屏蔽T tmp = a;//...return tmp; }

2、使用模板形參名字的限制

用作模板形參的名字不能在模板內部重用:

template <class T> T calc(const T &a,const T &b) {typedef double T; //ErrorT tmp = a;//...return tmp; }

這一限制還意味著模板形參的名字僅僅能在同一模板形參表中使用一次:

template <class T,class T> T calc(const T &a,const T &b); //Error

正如能夠重用函數形參名字一樣,模板形參的名字也能在不同模板中重用:

template <class T> T calc(const T &a,const T &b);template <class T> int compare(const T &,const T&); //OK

3、模板聲明

像其它隨意函數或類一樣,對于模板能夠僅僅聲明而不定義。聲明必須指出函數或類是一個模板:

template <class T> int compare(const T &,const T&);

同一模板的聲明和定義中,模板形參的名字不必同樣:

template <class T> T calc(const T &,const T &);template <typename U> U calc(const U&,const U&);template <class Type> Type calc(const Type &,const Type &);

每一個模板類型形參前面必須帶上keywordclasstypename,每一個非類型形參前面必須帶上類型名字,省略keyword或類型說明符是錯誤的:

template<typename T,U> T calc(const T &,const U &); //Errortemplate<typename T,class U> T calc(const T &,const U &); //OK
//P531 習題16.9 template <typename Type,typename T> Type find(Type begin,Type end,const T &val) {while (begin != end){if (*begin == val){return begin;}++ begin;}return end; }int main() {int ia[] = {01,1,1,999,2,3,2,34,4,3,4};int *p;if ((p = find(ia,ia+sizeof(ia)/sizeof(*ia),999)) != ia + sizeof(ia)/sizeof(*ia)){cout << *p << endl;}else{cout << "Not Found!" << endl;}vector<int> iVec(ia,ia + sizeof(ia)/sizeof(*ia));vector<int>::iterator iter;if ((iter = find(iVec.begin(),iVec.end(),888)) != iVec.end()){cout << *iter << endl;}else{cout << "Not Found!" << endl;}ifstream inFile("input");vector<string> strVec;string val;while (inFile >> val){strVec.push_back(val);}vector<string>::iterator it;if ((it = find(strVec.begin(),strVec.end(),"hello")) != strVec.end()){cout << *it << endl;}else{cout << "Not Found!" << endl;} }

總結

以上是生活随笔為你收集整理的C++ Primer 学习笔记_75_模板与泛型编程 --模板定义的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。