1. 程式人生 > >c++中模板類的使用

c++中模板類的使用

最近在資料結構的課程中很多周圍的同學對模板類的使用抱有很大的困惑,看也能看懂,但寫起來總是不明白……
那就首先得知道為什麼要用模板。
假設我有一個方法

void swap(int& a,int& b)
{
    int c = a;
    a = b;
    b = c
}

作用是交換兩個引數,實現起來也很簡單,
乍看上去挺好的,但我現在有另外一個需求,我需要交換兩個double,這時候你可能會說,再過載一個void swap(double& a,double& b);不就行了
但是在這裡我們觀察可以發現,swap函式的實現,其實與它的引數的型別是無關的。也就是,double,int,或者別的什麼,它的實現方法都是c=a;a=b;b=c;
所以,就有了模板這種東西。模板用template宣告,這裡的class可以用typename替換,兩者完全一樣。T是我們給這種臨時資料型別取的名字,也可以隨便改。在模板的作用下,這個方法可以改成

template<class T>
void swap(T&a,T&b)
{
    T c = a;
    a = b;
    b = c;
}

也就是說,這裡的T相當於我們定義了一種新的資料型別(class並不代表我們定義了一個類),只是這種資料型別很特殊,可以隨你傳的值變化。當你呼叫這個函式的時候向其中傳入的是什麼型別,T就會變成什麼型別。

注意! 但是,雖然T可變,但是一旦確定下來之後,它就是確定的,比如swap裡不能傳一個int,一個double,必須統一。
template<class T>作用域只有下面的一個程式碼塊,也就是一個方法體或者一個類。在swap之下再用T,是會報錯的。

上面是模板最簡單的用法,作用於單個函式,適用於演算法一樣,但型別不一樣,且演算法與型別無關的情況。

對類使用模板

類似於上面的情況,在建立一些類的時候我們也有使用模板的需要。比如,我建立了一個連結串列的類Chain,和連結串列節點類ChainNode。

class ChainNode
{
private:
    ChainNode();
    int data;
    ChainNode *next;
};

在定義類ChainNode時,我們需要儲存兩個值,一個是資料,一個是指向下一個ChainNode的指標。我們建立這個連結串列類,一定是希望它適合多種場合,可重複利用,但是定義ChainNode時我們必須要指定資料的儲存型別。也就是說,ChainNode定義時data的型別是int,那Chain就只能儲存int,要想儲存double,那我們似乎只能重寫Chain類,最好的情況也是重寫ChainNode類。

但我們現在不需要這麼麻煩,我們有模板這個好用的工具,現在看以下程式碼:

template <class T>
class ChainNode
{
private:
    ChainNode();
    T data;
    ChainNode *next;
};

這樣,只需要我們在使用時,如下宣告ChainNode

ChainNode<int> node1;
ChainNode<double> node2;

即可方便地使用ChainNode的int版和double版。注意如上程式碼,不同於函式是自動判斷,帶模板的類在使用時需要顯式指定。當ChainNode後面跟< int>時,你可以簡單地理解為把上面的ChainNode類中所有的T替換成了int。

需要注意的是,當我們在類的外部實現方法(這是合理而必要的)時,不同於不使用模板時的定義

ChainNode::ChainNode()
{
    data = 0;
    next = 0;
}

我們現在需要

template <class T>
ChainNode<T>::ChainNode()
{
    data = 0;
    next = 0;
}

不論該函式是否使用了模板。

在new出帶有模板的類的物件的時候,也有稍許不同,

ChainNode<int> *node = new ChainNode<int>();

如果ChainNode類有一個靜態方法sMethod(),呼叫時:

ChainNode<int>::sMethod();

另外,我們現在Chain類是需要儲存一個ChainNode的指標first指向連結串列的頭節點,那這時候怎麼做呢?
答案是把Chain類也用上模板。

template<class U>//防止跟上面的T搞混表不清意思
class Chain{
public:
    //上略
private:
    ChainNode<U> *first;
    //下略
};

這樣意思就很清楚了,ChainNode宣告的時候需要指定型別?那我就再指定個模板給你先拿著吧,等我使用Chain時,我指定好U這個型別具體是什麼,自然也就把U傳到ChainNode< U>裡了。

其實根據這個思路,我們甚至可以這樣用

ChainNode<ChainNode<int>>//儲存 儲存int資料的節點 的節點

類似二維陣列,這叫做遞迴呼叫模板

模板還有一些更高階的用法,這裡就不介紹啦,大家自行摸索吧