C++中的模板(templates) (轉)
作者:苗新東
什麼是模板
模板是根據引數型別生成和類的機制(有時稱為“引數決定型別”)。透過使用模板,可以只設計一個類來處理多種型別的資料,而不必為每一種型別分別建立類。
例如,建立一個型別函式來返回兩個引數中較小的一個,如果不使用Templates,必須要編寫一系列如下的函式:
// min for ints:namespace prefix = o ns = "urn:schemas--com::office" />
int min( int a, int b )
return ( a < b ) ? a : b;
// min for longs
long min( long a, long b )
return ( a < b ) ? a : b;
// min for chars
char min( char a, char b )
return ( a < b ) ? a : b;
//etc...
使用templates,可以減少重複部分,形成一個函式:
template
return ( a < b ) ? a : b;
模板能夠減少量並提高程式碼的機動性而不會降低型別安全。
何時使用模板
模板經常被用來實現如下功能:
Ø 建立一個型別安全的集合類(例如,堆疊)用來處理各種型別的資料
Ø 為函式新增額外的型別檢查以避免獲得空指標
Ø 合併運算子過載組來修改型別行為(例如智慧指標smart pointer)
大多數以上應用可以不用模板實現;但是,模板具有以下幾個優勢:
Ø 開發容易。你可以只為你的類或函式建立一個普通的版本代替手工建立特殊情況處理。
Ø 理解容易。模板為抽象型別資訊提供了一個直截了當的方法。
Ø 型別安全。模板使用的型別在編譯時是明確的,可以在發生錯誤之前進行型別檢查。
函式模板(function templates)
使用函式模板,你可以指定一組基於相同程式碼但是處理不同型別或類的函式,例如:
template
{
T c( a );
a = b; b = c;
}
這段程式碼定義了一個函式家族來函式的引數值。從這個template你可以產生一系列函式,不僅可以交換整型、長整型,而且可以交換定義型別,如果類的建構函式和賦值運算子被適當地定義,MySwap函式甚至可以交換類。
另外,函式模板可以阻止你交換不同型別的,因為編譯器在編譯時知道引數a和b的型別。
你可以像一個普通函式一樣呼叫一個函式模板函式;不需要特殊的語法。例如:
int i, j;
char k;
MySwap( i, j ); //OK
MySwap( i, k ); //Error, different types.
可以對函式模板的template引數作外部說明,例如:
template
void g(char j) {
f
}
當template引數在外部說明時,普通固定的型別轉換會轉換函式的引數為相應的函式模板引數。在上面的的例子中,編譯器會將(char j)轉換成整型
類别範本(class templates)
可以使用類别範本建立對一個型別進行操作的類家族。
template
{
public:
TempClass( void );
~TempClass( void );
int MemberSet( T a, int b );
private:
T Tarray[i];
int arraysize;
};
在這個例子中,模板類使用了兩個引數,一個型別T和一個整數i,T引數可以傳遞一個型別,包括結構和類,i引數必須傳第一個整數,因為I在編譯時是一個常數,你可以使用一個標準陣列宣告來定義一個長度為i的成員陣列
模板與宏的比較(Templates vs. Macros)
在很多方面,模板類似預處理宏,用給定的型別代替模板的變數。然而,模板和宏有很大的區別:
宏:
#define min(i, j) (((i) < (j)) ? (i) : (j))
模板:
template
使用宏會帶來如下問題:
Ø 編譯器沒有辦法檢查宏的引數的型別是否一致。宏的定義中缺少特定型別的檢查。
Ø 引數i和j被被呼叫了2次。例如,如果任一個引數有增量,增量會被加兩次。
Ø 因為宏被預處理編譯,編譯器錯誤資訊會指向編譯處的宏,而不是宏定義本身。而且,在編譯階段宏會在編譯表中顯露出來。
模板和空指標的比較(Templates VS. Void Pointers)
現在很多用空指標實現的函式可以用模板來實現。空指標經常被用來允許函式處理未知型別的資料。當使用空指標時,編譯器不能區分型別,所以不能處理型別檢查或型別行為如使用該型別的運算子、運算子過載或構造和析構。
使用模板,你可以建立處理特定型別的資料的函式和類。型別在模板定義裡看起來是抽象的。但是,在編譯時間編譯器為每一個指定的型別建立了這個函式的一個單獨版本。這使得編譯器可以使用類和函式如同他們使用的是指定的型別。模板也可以使程式碼更簡潔,因為你不必為符合型別如結構型別建立特殊的程式。
模板和集合類(Templates and Collection Classes)
模板是實現集合類的一個好方法。第四版及更高版本的Microsoft Foundation Class Library使用模板實現了六個集合類:CArray, CMap, CList, CTypedPtrArray, CtypedPtrList和 CtypedPtrMap。
MyStack集合類是一個簡單的堆疊的實現。這裡有兩個模板引數,T和i,指定堆疊中的元素型別和堆疊中項數的最大值。push 和 pop成員函式新增和刪除堆疊中的項,並在堆疊底部增加。
template
{
T StackBuffer[i];
int cItems;
public:
void MyStack( void ) : cItems( i ) {};
void push( const T item );
T pop( void );
};
template
{
if( cItems > 0 )
StackBuffer[--cItems] = item;
else
throw "Stack overflow error.";
return;
}
template
{
if( cItems < i )
return StackBuffer[cItems++]
else
throw "Stack underflow error.";
}
模板和智慧指標(Templates and Smart Pointers)
C++允許你建立“智慧指標”(“smart pointer”)類囊括指標和過載指標運算子來為指標操作增加新的功能。模板允許你建立普通包裝來囊括幾乎所有型別的指標。
如下的程式碼概括了一個簡單的計數垃圾收集者參考。模板類Ptr
#include
#define TRACE printf
class RefCount {
int crefs;
public:
RefCount(void) { crefs = 0; }
~RefCount() { TRACE("gooye(%d)n", crefs); }
void upcount(void) { ++crefs; TRACE("up to %dn", crefs);}
void downcount(void)
{
if (--crefs == 0)
{
delete this;
}
else
TRACE("downto %dn", crefs);
}
};
class Sample : public RefCount {
public:
void doSomething(void) { TRACE("Did somethingn");}
};
template
T* p;
public:
Ptr(T* p_) : p(p_) { p->upcount(); }
~Ptr(void) { p->downcount(); }
operator T*(void) { return p; }
T& operator*(void) { return *p; }
T* operator->(void) { return p; }
Ptr& operator=(Ptr
{return operator=((T *) p_);}
Ptr& operator=(T* p_) {
p->downcount(); p = p_; p->upcount(); return *this;
}
};
int main() {
Ptr
Ptr
p = p2; // #1 will have 0 crefs, so it is destroyed;
// #2 will have 2 crefs.
p->doSomething();
return 0;
// As p2 and p go out of pe, their destructors call
// downcount. The cref variable of #2 goes to 0, so #2 is
// destroyed
}
類RefCount 和 Ptr
例如,考慮一個用來建立和處理垃圾收集的類,符號、字串等等。根據類别範本Ptr
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990988/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 使用IntelliJ IDEA中的Live Templates自定義程式碼模板IntelliJIdea
- myeclipse_templates模板圖解Eclipse圖解
- C++ Templates (2.3 類别範本的區域性使用 Partial Usage of Class Templates)C++
- Pages模板Templates for Pages DesiGN讓您的工作更出色
- 400多種Numbers模板 DesiGN for Numbers Templates for macMac
- Templates for Pages DesiGN for mac(Pages模板) v7.1中文版Mac
- 關於C++當中的“模板函式”C++函式
- Spring Boot + Mybatis + Spring MVC環境配置(五):templates模板使用Spring BootMyBatisMVC
- Pages模板:Templates for Pages DesiGN for mac v7.4啟用版Mac
- Mac宣傳單設計模板套件——DesiGN Flyers Templates for MacMac套件
- C++——模板C++
- C++ 模板C++
- C++中的輾轉相除法C++
- templates
- 詳解C++的模板中typename關鍵字的用法C++
- c++11-17 模板核心知識(十四)—— 解析模板之依賴型模板名稱 Dependent Names of Templates(.template/->template/::template)C++
- 在VS2017中建立C++的程式碼塊模板C++
- C++ Templates (2.1 類别範本Stack的實現 Implementation of Class Template Stack)C++
- Variadic Templates
- Veriadic templates
- Templates by HanggoashGo
- Django中的templates(你的HTML頁面放哪裡)DjangoHTML
- c++ 模板模板引數("Template Template Parameters")C++
- c++函式模板C++函式
- C++模板沉思錄C++
- C++ Templates (2.2 使用Stack類别範本 Use of Class Template Stack )C++
- c++中數字和字串的轉換C++字串
- C++ 表示式中的型別轉換C++型別
- C++模板沉思錄(上)C++
- C++開發:template,模板C++
- C++泛型一:模板C++泛型
- C++函式模板案例C++函式
- C++中string、char *、char[]、const char*的轉換C++
- c++模板類的使用,編譯的問題C++編譯
- c++中字元、字串和數字間的轉換C++字元字串
- 聊聊 C++ 中的四種型別轉換符C++型別
- 模板方法模式(c++實現)模式C++
- c++可變模板引數C++
- 關於C++中在模板引數中使用Lambda表示式的問題C++