我們從乙個很簡單的問題來進入泛型程式設計:
question:如何寫乙個通用的加法函式:
⑴、使用函式過載。針對每乙個所需相同行為的不同型別重新實現;
函式過載的缺點:
1、只要有 型別出現,就要重新新增對應函式;
2、除型別外,所有函式的函式體都相同,**的復用率不高;
3、如果函式知識返回值型別不同,函式過載不能解決;
4、乙個方法有問題,所有的方法都有問題,不好維護。
(2)、使用公共基類,將通用的**放在公共基類中;
公共基類的缺點:
1、借助公共基類來編寫通用**,將失去型別檢查的優點;
2、對於以後實現的許多類,都必須繼承某個特定的基類,**很難維護;
(3)、使用特殊的預處理
預處理的缺點:
巨集定義,不是函式,不能進行引數型別檢測。安全性不高;
因此,我們用了泛型程式設計:編寫與型別無關的邏輯**,是**復用的一種手段;模板是泛型程式設計的基礎;
函式模板:代表了乙個函式家族,該函式與型別無關,在使用時被引數化,根據實參型別產生函式的特定型別版本。
模板函式的格式:
注意:typename是用來定義模板的關鍵字,也可以使用class,建議使用typename,但是不能是使用struct
模板不是類或函式,編譯器用模板產生指定的類或函式的特定型別版本,產生模板特定型別的過程稱為函式模板例項化;
template
t add(t left, t right)
int main()
注意著裡模板的編譯和以往函式不同,編譯了2次:
1、例項化之前。檢查模板**本身,檢視是否出現錯誤;
2、在例項化期間,檢查模板**,檢視是否所有的呼叫都有效;
【實參推演:】
發生在隱式例項化的時候:從函式實參確定模板形參型別和值得過程稱為模板實參推斷,多個型別形參必須匹配
【型別形參轉換】
一般不會轉換實參已匹配已有的例項化,相反會產生新的例項化:(兩種轉換)
【1、const轉換】
接受const引用或者const指標的函式可以分別用非const歲次昂的引用或指標來呼叫
【2、陣列或函式到指標的轉換】
如果模板形參不是引用型別,則對陣列或函式型別的實參引用常規指標轉換。陣列實參將當做指向其第乙個元素的指標,函式實參當做指標函式型別的指標。
【模板引數】1、模板形參名字只能在模板形參之後到模板宣告或定義的末尾之間使用,遵循名字遮蔽規則;
typedef
double t;
template
//作用域開始
void funtest(t t)
//作用域結束
2、模板形參的名字在同一模板形參列表中只能使用一次
3、所有模板引數前面必須加上class或者typename關鍵字修飾
template
//模板引數重定義
void funtest(t t1, t t2)
{}int main()
template
//識別符號錯誤
void funtest(t t, u u)
{}int main()
【非模板引數】
非模板引數形參是模板內部定義的常量,在需要常量表示式的時候,可以使用廢模板型別引數
template
//預設的非模板型別引數
void funtest(t(&a)[n])//陣列的引用
}int main()
【模板函式過載】
int max(const int& left, const int& right)
templatet max(const t& left, const t& right)
int main()
【說明】
1、乙個非模板函式可以和乙個同名函式模板同時存在,而且該函式模板還可以被例項化為這個非模板函式
2、對於非模板函式和同名函式模板,如果其他條件都相同,在調動時會優先調動非模板函式而不會從模板中產生 乙個例項,如果模板可以產生乙個更好匹配的函式,那麼選擇模板;
3、顯式指定乙個空的模板實參列表,該語法告訴編譯器只有模板才能匹配這個呼叫,而且所有的模板引數都應該根據實參推演出來;
4、模板函式不允許自動型別轉換,但普通函式可以進行自動型別轉換;
【模板函式特化】在上述的模板函式過載中,雖然嗯呢該解決好多問題,但是並不能比較兩個字串的大小;
模板特化的格式:
template
const t& max(const t& left, const t& right)//特化基礎版本
template
<>
char*const &max(char* const& left, char* const& right)//特化版本
int main()
在特化的時候必須要有特化的基礎版本,並且基礎版本必須與特化版本函式的形參型別完全匹配,如果不匹配,編譯器將為模板定義中例項化乙個例項;
【注意:】
在上乙個特換版本中,有乙個問題是在基礎版本中的const t& left ,其中const修飾的是left;
template
void funtest(const t p)//根據原來的學習:t為int*的型別,const int* p;
int main()
其實模板類和模板函式在定義的時候區別不是很大:
//模板類格式:
template1,class 形參2,...>
class 類名
;
以模板格式實現動態順序表:
template
class seqlist
;template
seqlist::seqlist()
: _size(0)
, _capacity(10)
, _data(new t[_capacity])
{}template
seqlist::~seqlist()
int main()
在上述**中,模板類被編譯了3次(在模板函式中編譯了2次):
1、編譯模板本身;2、編譯器遇到模板時;2、模板例項化期間
【模板例項化】:
在上述**的main()函式中,物件的建立時,其實就是例項化的過程,第乙個建立時,t為int型,第二個建立時,t為double型,例項化出2個類;
模板類先簡單的做乙個介紹,在後面會就vector和list兩個容器介面卡做詳細的介面做實現;
泛型程式設計 模板
泛型程式設計 重點 1.熟悉模板的語法 2.模板的原理 3.理解 基礎語法 類和物件 模板 去解決c語言不足的問題和意義 使用模板,編寫跟型別無關的 例如在一些函式和類的時候,針對不同型別需要寫很多重複的 swap函式 類 比如我們想實現乙個資料結構棧stack,stack的多個物件,st1存int...
模板和泛型程式設計
在建立完成抽象操作的函式時,如 拷貝,反轉和排序,你必須定義多個版本以便能處理每一種資料型別。以比較兩個數的大小為例 includeusing namespace std int max int a,int b double max double a,double b int main 例如 tem...
模板與泛型程式設計
模板是泛型變成的基礎。泛型程式設計 編譯與型別無關的 是一種復用的方式,模板分為模板函式和模板類。模板函式是乙個通用的函式模板,而不是為每一種型別定義乙個新函式,乙個函式模板就像乙個公式,針對不同型別函式生成不同的函式版本。關鍵字 template 以 template 開始,後面跟乙個模板引數列表...