九、函數(shù)模板和類(lèi)模板

函數(shù)模板

在設(shè)計(jì)程序中的函數(shù)時(shí)赡鲜,可能會(huì)遇到函數(shù)中參數(shù)的類(lèi)型有差異空厌,但需要實(shí)現(xiàn)的功能類(lèi)似的情形。函數(shù)重載可以處理這種情形银酬。重載函數(shù)的參數(shù)表中蝇庭,可以寫(xiě)不同類(lèi)型的參數(shù),從而可以處理不同的情形捡硅。

函數(shù)模板的概念

為了提高效率哮内,實(shí)現(xiàn)代碼復(fù)用,C++提供了一種處理機(jī)制,即使用函數(shù)模板北发。函數(shù)在設(shè)計(jì)時(shí)并不使用實(shí)際的類(lèi)型纹因,而是使用虛擬的類(lèi)型參數(shù)。這樣可以不必為每種不同的類(lèi)型都編寫(xiě)代碼段琳拨。當(dāng)用實(shí)際的類(lèi)型來(lái)實(shí)例化這種函數(shù)時(shí)瞭恰,將函數(shù)模板與某個(gè)具體數(shù)據(jù)類(lèi)型連用。編譯器將以函數(shù)模板為樣板狱庇,生成一個(gè)函數(shù)惊畏,即產(chǎn)生了模板函數(shù),這個(gè)過(guò)程稱(chēng)為函數(shù)模板實(shí)例化密任。函數(shù)模板實(shí)例化的過(guò)程由編譯器完成颜启。程序設(shè)計(jì)時(shí)并不給出相應(yīng)數(shù)據(jù)的類(lèi)型,編譯時(shí)浪讳,由編譯器根據(jù)實(shí)際的類(lèi)型進(jìn)行實(shí)例化缰盏。

函數(shù)模板的示例

#include <iostream>
using namespace std;

template <typename T>
T abs(T x) {
    return x < 0 ? -x : x;
};

int main() {
    int n = -5;
    int m = 10;
    double d = -.5;
    float f = 3.2;
    
    cout << n << "的絕對(duì)值是:" << abs(n) << endl;//-5的絕對(duì)值是:5
    cout << m << "的絕對(duì)值是:" << abs(m) << endl;//10的絕對(duì)值是:10
    cout << d << "的絕對(duì)值是:" << abs(d) << endl;//-0.5的絕對(duì)值是:0.5
    cout << f << "的絕對(duì)值是:" << abs(f) << endl;//3.2的絕對(duì)值是:3.2

    return 0;
};

在主函數(shù)中,調(diào)用abs(n)時(shí)淹遵,編譯器根據(jù)實(shí)參n的類(lèi)型int口猜,推導(dǎo)出模板中的類(lèi)型參數(shù)Tint,然后實(shí)例化函數(shù)模板透揣,生成函數(shù)模板abs的一個(gè)實(shí)例:

int abs(int x) {
    return x < 0 ? -x : x;
};

這個(gè)實(shí)例即是模板函數(shù)济炎。

當(dāng)調(diào)用abs(d)時(shí),根據(jù)實(shí)參d的類(lèi)型double辐真,又實(shí)例化一個(gè)新的函數(shù):

double abs(double x) {
    return x < 0 ? -x : x;
};

這是另一個(gè)模板函數(shù)须尚。

實(shí)際上,函數(shù)模板不是一個(gè)具體的函數(shù)拆祈,編譯器不能為其生成可執(zhí)行代碼恨闪。定義函數(shù)模板后只是一個(gè)對(duì)函數(shù)功能框架的描述,當(dāng)它具體執(zhí)行時(shí)放坏,將根據(jù)傳遞的實(shí)參決定其功能咙咽。

雖然函數(shù)模板的使用形式與函數(shù)類(lèi)似,但二者有本質(zhì)的區(qū)別淤年,主要表現(xiàn)在以下3個(gè)方面:

  1. 函數(shù)模板本身在編譯時(shí)不會(huì)生成任何目標(biāo)代碼钧敞,只有當(dāng)通過(guò)模板生成具體的函數(shù)實(shí)例時(shí)才會(huì)生成目標(biāo)代碼。
  2. 被多個(gè)源文件引用的函數(shù)模板麸粮,應(yīng)當(dāng)連同函數(shù)體一同放在頭文件中溉苛,而不能像偶同函數(shù)那樣只將生命放在頭文件中。
  3. 函數(shù)指針也只能指向模板的實(shí)例弄诲,而不能指向模板本身愚战。

函數(shù)或函數(shù)模板調(diào)用語(yǔ)句的匹配順序

函數(shù)與函數(shù)模板也是允許重載的娇唯。在函數(shù)和函數(shù)模板名字相同的情況下,一條函數(shù)調(diào)用語(yǔ)句到底應(yīng)該被匹配成對(duì)哪個(gè)函數(shù)或哪個(gè)模板的調(diào)用呢寂玲?C++編譯器遵循以下先后順序塔插。

  1. 先找參數(shù)完全匹配的普通函數(shù)(不是由模板實(shí)例化得到的模板函數(shù))。
  2. 再找參數(shù)完全匹配的模板函數(shù)拓哟。
  3. 然后找實(shí)參經(jīng)過(guò)自動(dòng)類(lèi)型轉(zhuǎn)換后能夠匹配的普通函數(shù)想许。
  4. 如果上面的都找不到,則報(bào)錯(cuò)断序。

類(lèi)模板

類(lèi)模板概念

通過(guò)類(lèi)模板流纹,可以實(shí)例化一個(gè)個(gè)的類(lèi)。繼承機(jī)制也是在系列的類(lèi)之間建立某種聯(lián)系违诗,這兩種涉及多個(gè)類(lèi)的機(jī)制是有很大差異的漱凝。類(lèi)是相同類(lèi)型事物的抽象,有繼承關(guān)系的類(lèi)可以具有不同的操作较雕。而模板是不同類(lèi)型的事物具有相同的操作碉哑,實(shí)例化后的類(lèi)之間沒(méi)有聯(lián)系挚币,相互獨(dú)立亮蒋。

聲明類(lèi)模板的一個(gè)格式如下:

template <模板參數(shù)表>
class 類(lèi)模板名 {
    類(lèi)體定義
};

其中,模板參數(shù)表的形式與函數(shù)模板中的模板參數(shù)表完全一樣妆毕。類(lèi)體定義與普通類(lèi)的定義幾乎相同慎玖,只是在它的成員變量和成員函數(shù)中通常要用到模板的類(lèi)型參數(shù)。

類(lèi)模板的成員函數(shù)既可以在類(lèi)體內(nèi)進(jìn)行說(shuō)明笛粘,也額可以在類(lèi)體外進(jìn)行說(shuō)明趁怔。如果在類(lèi)體內(nèi)定義,則自動(dòng)成為內(nèi)聯(lián)函數(shù)薪前。如果需要在類(lèi)模板以外定義其成員函數(shù)润努,則要采用以下格式:

template <模板參數(shù)表>
返回類(lèi)型名 類(lèi)模板名<模板參數(shù)標(biāo)識(shí)符列表>::成員函數(shù)名(參數(shù)表) {
    函數(shù)體
};

類(lèi)模板聲明本身并不是一個(gè)類(lèi),它說(shuō)明了類(lèi)的一個(gè)家族示括。只有當(dāng)被其他代碼引用時(shí)铺浇,模板才根據(jù)引用的需要生成具體的類(lèi)。

不能使用類(lèi)模板來(lái)直接生成對(duì)象垛膝,因?yàn)轭?lèi)型參數(shù)是不確定的鳍侣,必須先為模板參數(shù)指定實(shí)參,即模板要實(shí)例化后吼拥,才可以創(chuàng)建對(duì)象倚聚。也就是說(shuō),當(dāng)使用類(lèi)模板創(chuàng)建對(duì)象時(shí)凿可,要隨類(lèi)模板名給出對(duì)應(yīng)于類(lèi)型形參或普通形參的具體實(shí)參惑折,格式如下:

類(lèi)模板名 <模板參數(shù)表> 對(duì)象名1,...,對(duì)象名n;
//或是
類(lèi)模板名 <模板參數(shù)表> 對(duì)象名1(構(gòu)造函數(shù)實(shí)參),...,對(duì)象名n(構(gòu)造函數(shù)實(shí)參);

編譯器由類(lèi)模板生成類(lèi)的過(guò)程稱(chēng)為類(lèi)模板的實(shí)例化。由類(lèi)模板實(shí)例化得到的類(lèi)稱(chēng)為模板類(lèi)。

要注意的是惨驶,與類(lèi)型形參相對(duì)應(yīng)的實(shí)參是類(lèi)型名矗积。

類(lèi)模板示例

二院組是常用的一種結(jié)構(gòu)〕ㄟ郑可以定義兩個(gè)值的二院組棘捣,如平面坐標(biāo)系下點(diǎn)的橫、縱坐標(biāo)組成的二元組休建。還可以定義兩個(gè)字符串的二元組乍恐,如字典中單詞與釋義組成的二元組。還可以定義學(xué)生姓名及其成績(jī)的二元組测砂。二元組的例子非常多茵烈,不勝枚舉。

如果要定義二元組類(lèi)砌些,則需要根據(jù)組成二元組的類(lèi)型定義很多不同的類(lèi)∥赝叮現(xiàn)在可以使用類(lèi)模板來(lái)解決問(wèn)題。

#include <ostream>
using namespace std;

template <class T>
class TestClass {
public:
    T buffer[10];
    T getData(int j);
};
template <class T>
T TestClass<T>::getData(int j) {
    return *(buffer + j);
};

int main() {
    TestClass<char> ClassInstA;//char取代T存璃,從而實(shí)例化出具體的類(lèi)
    int i;
    char cArr[6] = "abcde";
    
    for (i = 0; i < 5; i++) {
        ClassInstA.buffer[i] = cArr[i];
    }
    for (i = 0; i < 5; i++) {
        char result = ClassInstA.getData(i);
        cout << result << " ";
    }
    cout << endl;
    
    TestClass<double> ClassInstF;//實(shí)例化為另外一個(gè)具體的類(lèi)
    double fArr[6] = {12.1, 23.2, 34.3, 45.4, 56.5, 67.6};
    
    for (i = 0; i < 6; i++) {
        ClassInstF.buffer[i] = fArr[i] - 10;
    }
    for (i = 0; i < 6; i++) {
        double result = ClassInstF.getData(i);
        cout << result << " ";
    }
    cout << endl;
    //2.1 13.2 24.3 35.4 46.5 57.6
    
    return 0;
};

類(lèi)模板與繼承

類(lèi)之間允許繼承仑荐,類(lèi)模板之間也允許繼承。具體來(lái)說(shuō)纵东,類(lèi)模板和類(lèi)模板之間粘招、類(lèi)模板和類(lèi)之間可以互相繼承,它們之間的常見(jiàn)派生關(guān)系有以下4中情況:

  1. 普通類(lèi)繼承模板類(lèi)
  2. 類(lèi)模板繼承普通類(lèi)
  3. 類(lèi)模板繼承類(lèi)模板
  4. 類(lèi)模板繼承模板類(lèi)

根據(jù)類(lèi)模板示例化的類(lèi)即是模板類(lèi)偎球。

#include <iostream>
#include <string>
using namespace std;

template <class T>
class TBase {
public:
    T data1;
    void Print() {
        cout << "TBase::" << data1 << endl;
    };
};

template <class T1, class T2>
class TDerievd : public TBase<T1> {
public:
    T2 data2;
    void Print() {
        TBase<T1>::Print();
        cout << "TDerived::" << data2 << endl;
    };
};

int main() {
    TDerived<int, int> d;//類(lèi)模板實(shí)例化洒扎,并聲明對(duì)象d
    d.data1 = 5;
    d.data2 = 8;  
    d.Print();
    //TBase::5
    //TDerived::8
    
    TDerived<string, string> d2;
    d2.data1 = "happy";
    d2.data2 = "new year";
    d2.Print();
    //TBase::happy
    //TDerived::new year
    
    TDerived<int, string> d3;
    d3.data1 = "2020";
    d3.data2 = "new year";
    d3.Print();
    //TBase::2020
    //TDerived::new year

    return 0;
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市衰絮,隨后出現(xiàn)的幾起案子袍冷,更是在濱河造成了極大的恐慌,老刑警劉巖猫牡,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胡诗,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡镊掖,警方通過(guò)查閱死者的電腦和手機(jī)乃戈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)亩进,“玉大人症虑,你說(shuō)我怎么就攤上這事」檠Γ” “怎么了谍憔?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵匪蝙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我习贫,道長(zhǎng)逛球,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任苫昌,我火速辦了婚禮颤绕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘祟身。我一直安慰自己奥务,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布袜硫。 她就那樣靜靜地躺著氯葬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪婉陷。 梳的紋絲不亂的頭發(fā)上帚称,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音秽澳,去河邊找鬼闯睹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛肝集,可吹牛的內(nèi)容都是我干的瞻坝。 我是一名探鬼主播蛛壳,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼杏瞻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了衙荐?” 一聲冷哼從身側(cè)響起捞挥,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎忧吟,沒(méi)想到半個(gè)月后砌函,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溜族,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年讹俊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片煌抒。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡仍劈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寡壮,到底是詐尸還是另有隱情贩疙,我是刑警寧澤讹弯,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站这溅,受9級(jí)特大地震影響组民,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悲靴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一臭胜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧癞尚,春花似錦庇楞、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至临燃,卻和暖如春睛驳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背膜廊。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工乏沸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人爪瓜。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓蹬跃,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親铆铆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蝶缀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355