九、函數(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)??梢远x兩個(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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容