0. 所謂泛型程式設計就是獨立於任何特定型別的方式編寫**,使用泛型程式時,需要提供具體程式例項所操作的型別或者值。我們經常用到stl容器、迭代器、和演算法都是泛型程式設計的例子;
模板是c++支援引數化多型的工具,使用模板可以使使用者為類或者函式宣告一種一般模式,使得類中的某些資料成員或者成員函式的引數、返回值取得任意型別;
模板是一種對型別進行引數化的工具;
通常有兩種形式:函式模板和類模板;
函式模板針對僅引數型別不同的函式;
類模板針對僅資料成員和成員函式型別不同的類;
使用模板的目的就是能夠讓程式設計師編寫與型別無關的**。比如編寫了乙個交換兩個整型int 型別的swap函式,這個函式就只能實現int 型,對double,字元這些型別無法實現,要實現這些型別的交換就要重新編寫另乙個swap函式。使用模板的目的就是要讓這程式的實現與型別無關,比如乙個swap模板函式,即可以實現int 型,又可以實現double型的交換。
1) 模板定義很特殊。由template<…>處理的任何東西都意味著編譯器在當時不為它分配儲存空間,它一直處於等待狀態直到被乙個模板例項告知。在編譯器和聯結器的某一處,有一機制能去掉指定模板的多重定義。所以為了容易使用,幾乎總是在標頭檔案中放置全部的模板宣告和定義。
2) 在分離式編譯的環境下,編譯器編譯某乙個.cpp 檔案時並不知道另乙個.cpp 檔案的存在,也不會去查詢(當遇到未決符號時它會寄希望於聯結器)。這種模式在沒有模板的情況下執行良好,但遇到模板時就傻眼了,因為模板僅在需要的時候才會例項化出來,所以,當編譯器只看到模板的宣告時,它不能例項化該模板,只能建立乙個具有外部連線的符號並期待聯結器能夠將符號的位址決議出來。然而當實現該模板的.cpp檔案中沒有用到模板的例項時,編譯器懶得去例項化,所以,整個工程的.obj中就找不到一行模板例項的二進位制**,於是聯結器也黔驢技窮了。
普通定義形式
templateint func(const t &a1, const t &a2)template inline int func(const t &a1, const t&a2)
templatet1 func(const t2 &t2, const t3 &t3)
//呼叫方法
func(i, log);
如果型別的定義順序與呼叫順序不一樣的話, 則需要在申明的時候制定型別順序;
tempaltet3 func(const t1 &t1, t2 &t2)//呼叫方法
func(12, 34);
//定義方式template class queue;
//使用方法
queueqi;
template void func(t (&parm)[n])
發現錯誤一般分為三個階段:
1. 編譯模板定義本身,可以檢測模板本身的語法問題,例如漏掉分號,拼寫錯誤等;
2. 編譯器見到模板的使用時,檢測引數個數、型別是否合法;
3. 模板例項化期間,檢測型別相關的錯誤;
類模板在引用例項類模板類型別時例項化,函式模板在呼叫它或者用它對函式指標程序初始化或者賦值時例項化,在使用函式模板時,編譯器通常會為我們推斷模板實參;
當編譯器看到模板定義時,不立即產生**, 只有在看到模板呼叫時,編譯器才會產生對應的例項,型別相關的錯誤才會被檢查出來。
函式模板的例項化是由編譯程式在處理函式呼叫時自動完成的,而類模板的例項化必須由程式設計師在程式中顯式地指定。即函式模板允許隱式呼叫和顯式呼叫而類模板只能顯式呼叫。在使用時類模板必須加,而函式模板不必。
通常情況下,例項化乙個物件或者呼叫乙個函式時,編譯器不需要看到函式或者類的定義,只有在連線的時候才會去關心類或者函式的定義。但是模板不一樣, 編譯器在例項化模板時,必須看到模板的定義才會編譯通過。
//header file#ifndef xx_h_
#define xx_h_
template int func(t &t1, t&t2);
#include "oo.cpp" //模板定義檔案
#endif
templateint func(t &t1, t&t2)
template ret-type queue::member_func_name
template class screenprivate:
std::string screen;
std::string::size_type cursor;
std::string::size_type height, width;
};//例項化方法,引數必須是編譯時常量表示式
screen<24, 80> hp2621;
template class bar
foobar 的成員可以訪問bar類任意例項的private &protected 成員。
template class bar;
表示fool和templ_fcnt的任意例項都可以訪問bar的任意例項的private和protected成員。
模板類只授權對特定友元例項的訪問權
template class foo2;template class bar
更通用的形式
template class foo2;template void templ_fcnt(const t&);
template class bar
這樣每個型別的類模板例項與對應的型別友元建立了一一對映關係。
- 宣告依賴性
如果模板類授權給所有友元例項訪問private和protected成員時, 編譯器將友元宣告當做類或者函式的宣告對待;但是如果指定到特定型別時,必須在前面宣告類或者函式。參考上面特定模板友元關係 和 一般友元關係 的宣告。
同時,如果沒有提前告訴編譯器該友元是乙個模板,編譯器則認為友元是乙個普通非模板函式或者非模板類。
這個名字確實有點繞, 其本質意思就是模板類的成員函式也希望有自己的引數型別,看如下例子:
template class queuetemplate void assign(iter , iter);
private:
template void copy_elems(iter, iter);
}
在類模板的外部定義模板成員,必須包含類模板的形參和模板成員的模板形參:
template //類模板的形參tmeplate //成員模板形參
void queue::assign(iter begin, iter end)
與其他成員一樣,成員模板也只有在被使用的時候才會例項化。
template class bar;private:
static std::size_t ctr;
}
例項化原則是:相同型別的例項共享乙個static成員,例如bar 型別的例項共享乙個static 成員ctr,bar 型別的例項共享乙個static成員ctr;
- 使用方法
barbar1, bar2;size_t ct = bar::count();
template size_t foo::ctr = 0;
由於模板的定義中,其操作都是依賴例項化的型別是否支援該操作或者操作的結果與預期是否相匹配,例如:
template int compare(const type& t1, const type &t2)
在上面的例子中,如果用char* 去例項化模板時,函式將比較兩個指標,很明顯與預期的記過不相吻合。此時可以通過模板特例話來解決。
函式模板特例化形式如下:
- 關鍵字template 後面接一對空的尖括號(<>);
- 在接末班嗎和一堆尖括號,尖括號中制定這個特化定義的模板形參;
- 函式形參表;
- 函式體。
例如:
template <>int compare(const char *t1, const char *t2)
如果有多個模板形參,則依次排列即可。
template <>class queue
需要在類特化的外部定義普通成員函式時,成員之前不能加 template<>標記:
void queue::push(const char* val)
template <>void queue::push(const char* const &val)
template<>
void queue::pop()
現在,類型別queue
template class tem;//partial specialization :fixes t2 as int and allows t2 to vary.
template class tem
使用方法:
temfoo; //呼叫普通的類模板tembar; //呼叫偏特化版本
函式模板可以過載:可以定義有相同名字但形引數據或型別不同的多個函式模板, 也可以定義與函式模板有相同名字的普通非模板函式。
不過從實踐來看,設計既包含函式模板又包含非模板函式的過載函式集合是困難的,因為坑你會使函式的使用者感覺到奇怪,定義函式模板特化幾乎總是比使用非模板版本更好。
參考c++泛型程式設計基本概念_sevenjoin的部落格-csdn部落格_c++泛型程式設計
C 泛型程式設計 模板
在學習c c 過程中,我們可能常用幾種函式,由於傳入的引數不同,需要進行不同的函式的編寫,在c語言中需要根據引數和功能的不同重新編寫新的函式,而在c 中有函式過載這樣的機制,一定程度上解決了問題,但是 過載的函式僅僅只是型別不同,的復用率比較低,只要有新型別出現時,就需要增加對應的函式 的可維護性比...
C 泛型程式設計(模板)
2.類模板 我們先來看乙個概念 泛型程式設計 使用模板,編寫和型別無關的 沒有模板之前,一些函式或者類,針對不同的型別需要寫很多重複的 函式 比如交換函式swap,假如傳入的資料型別不同,int,char,double。我們要實現不同的型別物件函式。類 比如我們像實現乙個資料結構棧stack,sta...
模板 泛型程式設計
我們從乙個很簡單的問題來進入泛型程式設計 question 如何寫乙個通用的加法函式 使用函式過載。針對每乙個所需相同行為的不同型別重新實現 函式過載的缺點 1 只要有 型別出現,就要重新新增對應函式 2 除型別外,所有函式的函式體都相同,的復用率不高 3 如果函式知識返回值型別不同,函式過載不能解...