程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++ chapter 10——模板

C++ chapter 10——模板

編輯:關於C++

**模板的概念
函數模板
類模板
名空間**

一、模板的概念
C++的模板提供對邏輯結構相同的數據對象通用行為的定義。模板運算對象的類型不是實際的數據類型,而是一種參數化的類型。
一個帶類型參數的函數稱為函數模板,一個帶類型參數的類稱為類模板。

二、函數模板

1、函數模板的概念
函數模板的基本原理是通過數據類型的參數化,將一組算法相同但所處理數據類型不同的重載函數凝練成一個函數模板。編譯時,再由編譯器按照函數模板自動生成針對不同數據類型的重載函數定義代碼。
使用函數模板。對於函數模板,數據類型本身成了它的參數。

*2、函數模板的說明*
**格式:**template < typename T1, typename T2,… typename Tn>

template—模板說明關鍵字
typename—類型參數指定關鍵字(也可以是class)
T1,T2,…Tn—類型參數,是用戶定義標識符,可實例化為任何內部類型或用戶定義類型。

3、函數模板與模板函數
函數模板定義由模板說明和函數定義組成。
格式為:
template < typename T1,typename T2,…typename Tn>
<返回值類型> <函數名>(模板函數形參表)
{
//函數定義體
}
所有在模板說明的類型參數必須在函數定義中至少出現一次。函數參數表中可以使用類型參數,也可以使用一般參數。
注意:
(1)函數模板只是說明,不能直接執行,需要實例化為模板函數後才能執行。
(2)模板的類型參數由調用它的實際參數的具體數據類型替換,由編譯器生成一段真正可執行的代碼。這個過程稱為實例化。
(3)一個函數模板用類型實例化後,稱為模板函數

//eg10-1:用函數模板輸出不同類型的數組
#include 
using namespace std;

template   //定義函數模板
void outputArray(const T *array, int count) {
    for (int i = 0; i < count; i++)
        cout << array[i] << " ";
    cout << endl;
}

int main() {
    const int A_COUNT = 8, B_COUNT = 8, C_COUNT = 20;
    int a[A_COUNT] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    double b[B_COUNT] = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8 };
    char c[C_COUNT] = "Welcome!";

    cout << " a array contains:" << endl;
    outputArray(a, A_COUNT);
    cout << " b array contains:" << endl;
    outputArray(b, B_COUNT);
    cout << " c array contains:" << endl;
    outputArray(c, C_COUNT);
    return 0;
}

4、函數模板的優點
(1)函數模板方法克服了C語言用大量不同函數名表示相似功能的壞習慣;
(2)克服了宏定義不能進行參數類型檢查的弊端;
(3)克服了C++函數重載用相同函數名字重寫幾個函數的繁瑣。
因而,函數模板是C++中功能最強的特性之一,具有宏定義和重載的共同優點,是提高軟件代碼重用率的重要手段。

//eg10-2:用函數模板實現對n個元素的數組求最小值
#include 
using namespace std;

template 
T min(T a[], int n)
{
    int i;
    T minv = a[0];
    for (i = 1; ia[i])
            minv = a[i];
    return minv;
}
int main()
{
    int a[] = { 1, 3, 0, 2, 7, 6, 4, 5, 2 };
    double b[] = { 1.2, -3.4, 6.8, 9, 8 };
    cout << "a數組的最小值為:" << min(a, 9) << endl;
    cout << "b數組的最小值為:" << min(b, 4) << endl;
    return 0;
}
//eg10-3:求兩個不同類型數據的較大值
#include 
using namespace std;

template 
T1 Max(T1 x, T2 y)
{
    return x>(T1)y ? x : (T1)y;
}
int main()
{
    int i = 10, j = 56;
    float x1 = 50.34, x2 = 56.34;
    double y1 = 673.36, y2 = 465.972;
    cout << "the max of i,x1 is:" << Max(i, x1) << endl;
    cout << "the max of x1,y1 is:" << Max(x1, y1) << endl;
    cout << "the max of j,y2 is:" << Max(j, y2) << endl;
    return 0;
}

5、重載函數模板
函數模板與普通函數一樣,也可以重載。可以定義同名的函數模板,提供不同的參數和實現;也可以用其他非模板函數重載。

(1)函數模板的重載

重載函數模板便於定義類型參數,或者函數模板參數的類型、個數不相同所進行的類似操作。
例如,例10-3的Max函數模板可以重載為求數組最大元素的函數模板。

//例10-4:函數模板重載
#include "iostream"
using namespace std;

template 
T Max(T x, T y)
{
    return (x>y) ? x : y;
};

template 
T Max(T a[], int n)
{
    T temp;
    int i;
    temp = a[0];
    for (i = 1; itemp)
            temp = a[i];
    return temp;
}

int main()
{
    int i = 10, j = 56;
    float x1 = 50.34, x2 = 56.34;
    double y1 = 673.36, y2 = 465.972;
    double X[10] = { 1.2, 3.4, 8.9, 6.5, 9.3, 15.8, 3.8, 21.3, 11.2, 2.1 };
    cout << "the max of i,j is:" << Max(i, j) << endl;
    cout << "the max of x1,x2 is:" << Max(x1, x2) << endl;
    cout << "the max of y1,y2 is:" << Max(y1, y2) << endl;
    cout << "The max element of X is:" << Max(X, 10) << endl;
    return 0;
}

(2)用普通函數重載函數模板
函數模板實例化時,實際參數類型替換類型參數。雖然這種參數替換具有類型檢查功能,卻沒有普通函數傳值參數的類型轉換機制。

例如:
對函數模板
template
T Max(T x,T y)
{
return (x>y)?x:y;
};
調用時對應的兩個實際參數必須類型相同。若有:
int k;char c;
則調用Max(k,c); 將出現語法錯誤。為了解決這一問題,可以用非模板函數重載一個同名的函數模板。

//例10-5:用普通函數重載函數模板
#include 
using namespace std;
template 
T Max(T x, T y)
{
    return (x>y) ? x : y;
};
int Max(char a, int b)   //函數重載
{
    return(a>b ? a : b);
}
int main()
{
    int k = 98;
    char c = 'a';
    double y1 = 673.36, y2 = 465.972;
    cout << "the max of k, c is : " << Max(k, c) << endl;  //調用正確
    cout << "the max of c, k is : " << Max(c, k) << endl;  //調用正確
    cout << "the max of y1,y2 is:" << Max(y1, y2) << endl;
    return 0;
}

注意:
定義重載函數要注意避免二義性。
例如,在例10-5中,如果重載函數改為:
int Max(int a,int b)
{ return a>b?a:b;}
將出現二義性,在調用時無法正確匹配。
Max(k,k);
//錯誤,不知調用T Max(T,T)還是Max(int,int)?
Max(c,c); //錯誤

編譯器調用函數的匹配規則:

(1)尋找和使用最符合函數名和參數類型的函數,若找到則調用它。
(2)否則,尋找一個函數模板,將其實例化產生一個匹配的模板函數,若找到則調用它。
(3)否則,尋找可以通過類型轉換進行參數匹配的重載函數,若找到則調用它。

如果按以上步驟均未能找到匹配函數,則這個調用是錯誤的。
如果這個調用有多於一個的匹配選擇,則調用匹配出現二義性,也是錯誤的。

在調用函數模板的程序員看來,函數模板與普通函數沒有什麼區別。唯一不同的是,函數模板 就像是一個具有通用類型的函數,可以處理不同類型的數據。

三、類模板

(1)應用模板技術,可以將一組功能相同但所處理數據類型不同的類凝練成一個類模板。編譯時,再由編譯器按照類模板自動生成針對不同數據類型的類定義代碼。
(2)使用類模板可以為類聲明一種模式,使得類中的某些數據成員、某些成員函數的參數、某些成員函數的返回值,能取任意類型(包括基本類型和用戶自定義類型)。
(3)類模板與函數模板類似,它可以為各種不同的數據類型定義一種模板,在引用時使用不同的數據類型實例化該類模板,從而形成一個類的集合。

1、類模板與模板類
類模板由模板說明和類說明構成。格式為:
template
class 類名 { 類聲明體 };
template < typename Type >
返回類型 類名<類型名表>::成員函數名1(形參表)
{ 成員函數1定義體 }

template
返回類型 類名<類型名表>::成員函數名n(形參表)
{ 成員函數n定義體 }

//例10-6:用類模板來處理任意類型的鏈表
#include 
using namespace std;

template   //聲明模板
struct node         //定義結構體類型模板
{
    T val;          //val取任意類型,即模板參數類型
    node *next;
};

template    //聲明模板
class list           //定義類模板
{
    node  *head;  //此處node為結構體類型模板
    int size;
public:
    list(){ head = 0; size = 0; }
    bool insert(T val);    //參數取T類型
    bool deletes(T val);   //參數取T類型
    bool contains(T val);  //參數取T類型
    void print();
    ~list();
};

template
list::~list()     //定義函數模板
{
    node  *temp;  //node為結構體類型模板
    for (node *p = head; p;)
    {
        temp = p;
        p = p->next;
        delete temp;
    }
}
template
bool list::insert(T x)
{
    node *nodes = new node;
    if (nodes)
    {
        nodes->val = x;
        nodes->next = head;
        head = nodes;
        size++;
        return true;
    }
    return false;
}

template 
bool list::deletes(T x)
{
    node *temp;
    if (head->val == x)
    {
        temp = head->next;
        delete head;
        size--;
        head = temp;
        return true;
    }
    for (node *p = temp = head; p; temp = p, p = p->next)
        if (p->val == x)
        {
            temp->next = p->next;
            delete p;
            size--;
            return true;
        }
    return false;
}
template
bool list::contains(T x)
{
    for (node *p = head; p; p = p->next)
        if (p->val == x)
            return true;
    return false;
}
template
void list::print()
{
    for (node *p = head; p; p = p->next)
        cout << p->val << " ";
    cout << endl;
}

void main()
{
    list intlist;  //定義一個整型鏈表對象intlist,此時傳遞進來的模板類型參數為
    intlist.insert(34);
    intlist.insert(54);
    intlist.insert(78);
    intlist.insert(76);
    intlist.insert(54);
    intlist.print();
    list floatlist; //定義一個浮點型鏈表對象floatlist,此時傳遞進來的模板類型參數為
    floatlist.insert(34.56);
    floatlist.insert(65.4);
    floatlist.insert(7534.56);
    floatlist.insert(364.56);
    floatlist.print();
    list charlist; //定義一個字符串鏈表對象charlist,此時傳遞進來的模板類型參數為
    charlist.insert("windows");
    charlist.insert("object");
    charlist.insert("borland");
    charlist.insert("virtual_function");
    charlist.print();
}

首先定義一個結構體模板,它與類模板用法相同;再定義一個類模板,結構體模板和類模板取同樣的模板參數T。

說明:
(1)類模板的說明(包括成員函數定義)不是一個實實在在的類,只是對類的描述,稱為類模板(class template)。類模板必須用類型參數將其實例化為模板類後,才能用來生成對象。一般地,其表示形式為:
類模板名 <類型實參表> 對象名(值實參表)
(2)其中<類型實參表>表示將類模板實例化為模板類時所用到的類型(包括系統固有的類型和用戶已定義類型),<值實參表>表示將該模板類實例化為對象時其構造函數所用到的變量。一個類模板可以用來實例化多個模板類。
(3)類型參數必須至少在類說明中出現一次。
(4)類模板的成員函數都是函數模板,實現語法和函數模板類似。如果在類中定義(作為inline函數),不需要特別說明。如果在類外定義,則每個成員函數定義都要冠以模板參數說明,並且指定類名時要後跟類型參數。
(5)類模板在表示如數組、表、圖等數據結構特別重要,因為這些數據結構的表示和算法不受所包含的元素類型的影響。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved