欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
<C++實(shí)踐系列>C++中的模板(template)
<C++實(shí)踐系列>C++中的模板(template)
作者:張笑猛

提交者:eastvc 發(fā)布日期:2003-11-22 14:36:25
原文出處:http://objects.nease.net/


網(wǎng)上我最喜歡的技術(shù)文章是類(lèi)似某何君所著(zhù)“CVS快速入門(mén)”或者“UML reference card”之類(lèi),簡(jiǎn)短扼要,可以非??斓念I(lǐng)著(zhù)你進(jìn)入一個(gè)新天地。而對于比較長(cháng)的文章我通常是將其保存到硬盤(pán)上,然后準備著(zhù)“以后有時(shí)間”的時(shí)候再看,但它們通常的命運都是“閑坐說(shuō)玄宗”,直到某一天在整理硬盤(pán)時(shí)將它們以“不知所云”入罪,一并刪除。

 這篇小文主要是針對剛剛接觸模板概念的讀者,希望能幫助讀者學(xué)習模板的使用。為了避免本文也在諸公的硬盤(pán)上遭逢厄運,我決定寫(xiě)的短些。“以后有時(shí)間”的時(shí)候再補充些內容。

TOC

1. 簡(jiǎn)介

2. 語(yǔ)法

3. 使用技巧
  3.1 語(yǔ)法檢查
  3.2 繼承
  3.3 靜態(tài)成員
3.4 模板類(lèi)的運用

4. 參考資料

 

1. 簡(jiǎn)介

模板是C++在90年代引進(jìn)的一個(gè)新概念,原本是為了對容器類(lèi)(container classes)的支持[1],但是現在模板產(chǎn)生的效果已經(jīng)遠非當初所能想象。

簡(jiǎn)單的講,模板就是一種參數化(parameterized)的類(lèi)或函數,也就是類(lèi)的形態(tài)(成員、方法、布局等)或者函數的形態(tài)(參數、返回值等)可以被參數改變。更加神奇的是這里所說(shuō)的參數,不光是我們傳統函數中所說(shuō)的數值形式的參數,還可以是一種類(lèi)型(實(shí)際上稍微有一些了解的人,更多的會(huì )注意到使用類(lèi)型作為參數,而往往忽略使用數值作為參數的情況)。

舉個(gè)常用的例子來(lái)解釋也許模板就從你腦袋里的一個(gè)模糊的概念變成活生生的代碼了:

在C語(yǔ)言中,如果我們要比較兩個(gè)數的大小,常常會(huì )定義兩個(gè)宏:

#define min(a,b) ((a)>(b)?(b):(a))
#define max(a,b) ((a)>(b)?(a):(b))

這樣你就可以在代碼中:

return min(10, 4);

或者:

return min(5.3, 18.6);

這兩個(gè)宏非常好用,但是在C++中,它們并不像在C中那樣受歡迎。宏因為沒(méi)有類(lèi)型檢查以及天生的不安全(例如如果代碼寫(xiě)為min(a++, b--);則顯然結果非你所愿),在C++中被inline函數替代。但是隨著(zhù)你將min/max改為函數,你立刻就會(huì )發(fā)現這個(gè)函數的局限性 —— 它不能處理你指定的類(lèi)型以外的其它類(lèi)型。例如你的min()聲明為:

int min(int a, int b);

則它顯然不能處理float類(lèi)型的參數,但是原來(lái)的宏卻可以很好的工作!你隨后大概會(huì )想到函數重載,通過(guò)重載不同類(lèi)型的min()函數,你仍然可以使大部分代碼正常工作。實(shí)際上,C++對于這類(lèi)可以抽象的算法,提供了更好的辦法,就是模板:

template <class T> const T & min(const T & t1, const T & t2) {
    return t1>t2?t2:t1;
}

這是一個(gè)模板函數的例子。在有了模板之后,你就又自由了,可以像原來(lái)在C語(yǔ)言中使用你的min宏一樣來(lái)使用這個(gè)模板,例如:

return min(10,4);

也可以:

return min(5.3, 18.6)

你發(fā)現了么?你獲得了一個(gè)類(lèi)型安全的、而又可以支持任意類(lèi)型的min函數,它是否比min宏好呢?

當然上面這個(gè)例子只涉及了模板的一個(gè)方面,模板的作用遠不只是用來(lái)替代宏。實(shí)際上,模板是泛化編程(Generic Programming)的基礎。所謂的泛化編程,就是對抽象的算法的編程,泛化是指可以廣泛的適用于不同的數據類(lèi)型。例如我們上面提到的min算法。

2. 語(yǔ)法

你千萬(wàn)不要以為我真的要講模板的語(yǔ)法,那太難為我了,我只是要說(shuō)一下如何聲明一個(gè)模板,如何定義一個(gè)模板以及常見(jiàn)的語(yǔ)法方面的問(wèn)題。

template<> 是模板的標志,在<>中,是模板的參數部分。參數可以是類(lèi)型,也可以是數值。例如:

template<class T, T t>
class Temp{
public:
    ...
    void print() { cout << t << endl; }
private:
    T t_;
};

在這個(gè)聲明中,第一個(gè)參數是一個(gè)類(lèi)型,第二個(gè)參數是一個(gè)數值。這里的數值,必須是一個(gè)常量。例如針對上面的聲明:

Temp<int, 10> temp; // 合法

int i = 10;
Temp<int, i> temp; // 不合法

const int j = 10;
Temp<int, j> temp; // 合法

參數也可以有默認值:

template<class T, class C=char> ...

默認值的規則與函數的默認值一樣,如果一個(gè)參數有默認值,則其后的每個(gè)參數都必須有默認值。

參數的名字在整個(gè)模板的作用域內有效,類(lèi)型參數可以作為作用域內變量的類(lèi)型(例如上例中的T t_),數值型參數可以參與計算,就象使用一個(gè)普通常數一樣(例如上例中的cout << t << endl)。

模板有個(gè)值得注意的地方,就是它的聲明方式。以前我一直認為模板的方法全部都是隱含為inline的,即使你沒(méi)有將其聲明為inline并將函數體放到了類(lèi)聲明以外。這是模板的聲明方式給我的錯覺(jué),實(shí)際上并非如此。我們先來(lái)看看它的聲明,一個(gè)作為接口出現在頭文件中的模板類(lèi),其所有方法也都必須與類(lèi)聲明出現在一起。用通俗的話(huà)來(lái)說(shuō),就是模板類(lèi)的函數體也必須出現在頭文件中(當然如果這個(gè)模板只被一個(gè)C++程序文件使用,它當然也可以放在.cc中,但同樣要求類(lèi)聲明與函數體必須出現在一起)。這種要求與inline的要求一樣,因此我一度認為它們隱含都是inline的。但是在Thinking In C++[2]中,明確的提到了模板的non-inline function,就讓我不得不改變自己的想法了??磥?lái)正確的理解應該是:與普通類(lèi)一樣,聲明為inline的,或者雖然沒(méi)有聲明為inline但是函數體在類(lèi)聲明中的才是inline函數。

澄清了inline的問(wèn)題候,我們再回頭來(lái)看那些我們寫(xiě)的包含了模板類(lèi)的丑陋的頭文件,由于上面提到的語(yǔ)法要求,頭文件中除了類(lèi)接口之外,到處充斥著(zhù)實(shí)現代碼,對用戶(hù)來(lái)說(shuō),十分的不可讀。為了能像傳統頭文件一樣,讓用戶(hù)盡量只看到接口,而不用看到實(shí)現方法,一般會(huì )將所有的方法實(shí)現部分,放在一個(gè)后綴為.i或者.inl的文件中,然后在模板類(lèi)的頭文件中包含這個(gè).i或者.inl文件。例如:

// start of temp.h
template<class T> class Temp{
public:
    void print();
};

 #include "temp.inl"
// end of temp.h

// start of temp.inl
template<class T> void Temp<T>::print() {
    ...
}
// end of temp.inl

通過(guò)這樣的變通,即滿(mǎn)足了語(yǔ)法的要求,也讓頭文件更加易讀。模板函數也是一樣。

普通的類(lèi)中,也可以有模板方法,例如:

class A{
public:
    template<class T> void print(const T& t) { ...}
    void dummy();
};

對于模板方法的要求與模板類(lèi)的方法一樣,也需要與類(lèi)聲明出現在一起。而這個(gè)類(lèi)的其它方法,例如dummy(),則沒(méi)有這樣的要求。

3. 使用技巧

知道了上面所說(shuō)的簡(jiǎn)單語(yǔ)法后,基本上就可以寫(xiě)出自己的模板了。但是在使用的時(shí)候還是有些技巧。

3.1 語(yǔ)法檢查

對模板的語(yǔ)法檢查有一部分被延遲到使用時(shí)刻(類(lèi)被定義[3],或者函數被調用),而不是像普通的類(lèi)或者函數在被編譯器讀到的時(shí)候就會(huì )進(jìn)行語(yǔ)法檢查。因此,如果一個(gè)模板沒(méi)有被使用,則即使它包含了語(yǔ)法的錯誤,也會(huì )被編譯器忽略,這是語(yǔ)法檢查問(wèn)題的第一個(gè)方面,這不常遇到,因為你寫(xiě)了一個(gè)模板就是為了使用它的,一般不會(huì )放在那里不用。與語(yǔ)法檢查相關(guān)的另一個(gè)問(wèn)題是你可以在模板中做一些假設。例如:

template<class T> class Temp{
public:
    Temp(const T & t): t_(t) {}
    void print() { t.print();}
private:
    T t_;
};

在這個(gè)模板中,我假設了T這個(gè)類(lèi)型是一個(gè)類(lèi),并且有一個(gè)print()方法(t.print())。我們在簡(jiǎn)介中的min模板中其實(shí)也作了同樣的假設,即假設T重載了'>'操作符。

因為語(yǔ)法檢查被延遲,編譯器看到這個(gè)模板的時(shí)候,并不去關(guān)心T這個(gè)類(lèi)型是否有print()方法,這些假設在模板被使用的時(shí)候才被編譯器檢查。只要定義中給出的類(lèi)型滿(mǎn)足假設,就可以通過(guò)編譯。

之所以說(shuō)“有一部分”語(yǔ)法檢查被延遲,是因為有些基本的語(yǔ)法還是被編譯器立即檢查的。只有那些與模板參數相關(guān)的檢查才會(huì )被推遲。如果你沒(méi)有寫(xiě)class結束后的分號,編譯器不會(huì )放過(guò)你的。

3.2 繼承

模板類(lèi)可以與普通的類(lèi)一樣有基類(lèi),也同樣可以有派生類(lèi)。它的基類(lèi)和派生類(lèi)既可以是模板類(lèi),也可以不是模板類(lèi)。所有與繼承相關(guān)的特點(diǎn)模板類(lèi)也都具備。但仍然有一些值得注意的地方。

假設有如下類(lèi)關(guān)系:

template<class T> class A{ ... };
 |
+-- A<int> aint;
 |
+-- A<double> adouble;

則aint和adouble并非A的派生類(lèi),甚至可以說(shuō)根本不存在A(yíng)這個(gè)類(lèi),只有A<int>和A<doubl>這兩個(gè)類(lèi)。這兩個(gè)類(lèi)沒(méi)有共同的基類(lèi),因此不能通過(guò)類(lèi)A來(lái)實(shí)現多態(tài)。如果希望對這兩個(gè)類(lèi)實(shí)現多態(tài),正確的類(lèi)層次應該是:

class Abase {...};

template<class T> class A: public Abase {...};
 |
+-- A<int> aint;
 |
+-- A<double> adouble;

也就是說(shuō),在模板類(lèi)之上增加一個(gè)抽象的基類(lèi),注意,這個(gè)抽象基類(lèi)是一個(gè)普通類(lèi),而非模板。

再來(lái)看下面的類(lèi)關(guān)系:

template<int i> class A{...};
 |
+-- A<10> a10;
 |
+-- A<5> a5;

在這個(gè)情況下,模板參數是一個(gè)數值,而不是一個(gè)類(lèi)型。盡管如此,a10和a5仍然沒(méi)有共同基類(lèi)。這與用類(lèi)型作模板參數是一樣的。

3.3 靜態(tài)成員

與上面例子類(lèi)似:

template<class T> class A{ static char a_; };
 |
+-- A<int> aint1, aint2;
 |
+-- A<double> adouble1, adouble2;

這里模板A中增加了一個(gè)靜態(tài)成員,那么要注意的是,對于aint1和adouble1,它們并沒(méi)有一個(gè)共同的靜態(tài)成員。而aint1與aint2有一個(gè)共同的靜態(tài)成員(對adouble1和adouble2也一樣)。

這個(gè)問(wèn)題實(shí)際上與繼承里面講到的問(wèn)題是一回事,關(guān)鍵要認識到aint與adouble分別是兩個(gè)不同類(lèi)的實(shí)例,而不是一個(gè)類(lèi)的兩個(gè)實(shí)例。認識到這一點(diǎn)后,很多類(lèi)似問(wèn)題都可以想通了。

3.4 模板類(lèi)的運用

模板與類(lèi)繼承都可以讓代碼重用,都是對具體問(wèn)題的抽象過(guò)程。但是它們抽象的側重點(diǎn)不同,模板側重于對于算法的抽象,也就是說(shuō)如果你在解決一個(gè)問(wèn)題的時(shí)候,需要固定的step1 step2...,那么大概就可以抽象為模板。而如果一個(gè)問(wèn)題域中有很多相同的操作,但是這些操作并不能組成一個(gè)固定的序列,大概就可以用類(lèi)繼承來(lái)解決問(wèn)題。以我的水平還不足以在這么高的層次來(lái)清楚的解釋它們的不同,這段話(huà)僅供參考吧。

模板類(lèi)的運用方式,更多情況是直接使用,而不是作為基類(lèi)。例如人們在使用STL提供的模板時(shí),通常直接使用,而不需要從模板庫中提供的模板再派生自己的類(lèi)。這不是絕對的,我覺(jué)得這也是模板與類(lèi)繼承之間的以點(diǎn)兒區別,模板雖然也是抽象的東西,但是它往往不需要通過(guò)派生來(lái)具體化。

在設計模式[4]中,提到了一個(gè)模板方法模式,這個(gè)模式的核心就是對算法的抽象,也就是對固定操作序列的抽象。雖然不一定要用C++的模板來(lái)實(shí)現,但是它反映的思想是與C++模板一致的。

4. 參考資料

[1] 深度C++對象模型,Stanley B.Lippman, 侯捷譯

[2] Thinking In C++ 2nd Edition Volumn 1, Bruce Eckel

[3] 定義-- 英文為definition,意思是"Make this variable here",參見(jiàn)[2] p93

[4] Design Patterns - Elements of Reusable Object-Oriented Software GOF


本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
類(lèi)模板的定義及其使用
C 模板詳解(一)
C++的泛型編程和限制參數類(lèi)型的技術(shù)探討
template用法
C++中的類(lèi)模板詳細講述
<轉載>獨一無(wú)二的C++模板
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久