C++模板詳細整理

C++模板

1 模板的概念

模板 字面意思和模型相似,造一個東西,總會有一個模型爲基礎。如果以後有什麼改動,也要在模型的基礎上改在。 這麼想,大家都知道了 c++裏模板也一樣也是模型,那這個模型有什麼用呢 。

例如,我們希望編寫一個函數來比較倆個值,並指出第一個值,是小於?還是大於?還是等於,第二個值。在以前,我們可能想要定義多個函數,每個函數比較一種特定的類型的值。我們會寫個重載函數:

int compare(const string &v1,const string &v2)
{
    if(v1<v2) 
        return 1;
    if(v2<v1)
        return -1;
    return 0;
}


int compare(const double&v1,const double &v2)
{
    if(v1<v2) 
        return 1;
    if(v2<v1)
        return -1;
    return 0;
}

這兩個函數幾乎相同,唯一的差異就是參數類型不同,函數體則完全相同。

如果對每種希望比較的類型都不得不重複定義完全一樣的函數體,是非常容易出錯的 。甚至讓人崩潰(在我以前不知道模板的時候)
但是模板出現後,就大大不一樣了,很方便,用法也很簡單。接下來學習簡單的函數模板。

1.1 函數模板
我們可以定義一個通用的函數模板,而不是爲每個類型定義一個新函數。一個函數模板就是一個模型一個公式,可以生成特定類型的函數版本。compare模板可以像這樣定義。

template <typename T>
int compare (const T &v1 , const T &v2)
{
    if(v1<v2)return 1;
    if(v2<v1)return -1;
    return 0;
}

1.1.1 函數模板的格式:

 template <class 形參名,class 形參名,......> 返回類型 函數名(參數列表)
 {
   函數體
 }

其中template和class,沒錯,他兩是一樣的。在這裏typename 和class沒區別

以關鍵字 template開始,後面跟一個模板參數列表。用< >包圍起來。

1.1.2 實例化函數模板
當我們調用一個函數模板時候,編譯器 用 函數的實參 來爲我們推斷 模板的實參類型。比如,我們調用上面的compar時候,編譯器就知道自己的模板參數T是什麼類型了。

cout << compare(1,0)<<endl;  //T爲 int類型

實參類型是 int 編譯器會推斷出模板實參 爲 int ,並將它綁定到模板參數 T 上。
接着,編譯器根據 他自己推斷出的 模板參數 來爲我們 實例化一個特定的函數,(就專門爲你制定的哦)。

當編譯器實例化一個模板時,她會使用實際的模板參數 代替 對應的模板參數 來創建出模板的一個新實例。
例如 :

//實例化出 int comnpare (const int &, const int &)
cout <<compare (1 , 0) << endl; //T 爲 int

//實例化出 int compare(const vector<int>&,const //vector<int>& 
 vector<int> vec{1,2,3},vwc2{4,5,6};
 cout <<compare(vec1,vec2)<<endl; // T爲 vector<int>

編譯器會實例化兩個不同的 compare。

1.2 類模板
類模板 是用來生成類的藍圖的,與函數模板不同的地方是,編譯器不能爲類模板推斷模板參數類型。 除非有額外的信息,接下來會說到。

定義類模板

1.2.1、類模板的格式爲:

    template<class  形參名,class 形參名,…>   class 類名

    { ... };
類似函數模板,類模板以關鍵字 template 開始,後面跟模板參數列表。在類模板及其中的成員,我們將模板參數當做替身,代替使用模板的時候,用戶需要提供類型 或 值。

以下是一些例子 大家參考一下。

// ClassTemplate.h

template<typename T1,typename T2>

class myClass{

private:

    T1 I;

    T2 J;

public:

    myClass(T1 a, T2 b);//Constructor

    void show();

};

//這是構造函數

//注意這些格式

template <typename T1,typename T2>

myClass<T1,T2>::myClass(T1 a,T2 b):I(a),J(b){}


//這是void show();

template <typename T1,typename T2>

void myClass<T1,T2>::show()

{

    cout<<"I="<<I<<", J="<<J<<endl;

}
// Test.cpp

#include<iostream>

#include"ClassTemplate.h"

using std::cout;

using std::endl;


void main()

{

    myClass<int,int> class1(3,5);

    class1.show();


    myClass<int,char> class2(3,"a");

    class2.show();


    myClass<double,int> class3(2.9,10);

    class3.show();

    system("PAUSE");

}

1.2.1 類模板和函數模板,都是以template開始,後接模板形參列表組成。模板形參不能爲空,一但聲明瞭類模板就可以用類模板的形參名,聲明類中的成員變量和成員函數。即可以在類中使用內置類型的地方都可以使用模板形參名來聲明。比如

  template<class T>
  class A {
  public:
   T a; T b;
   T hy(T c, T &d);
   };

//在類A中聲明瞭兩個類型爲T的成員變量a和b,還聲明瞭一個返回類型爲T帶兩個參數類型爲T的函數hy。

1.2.3
類模板對象的創建:比如一個模板類A,則使用類模板創建對象的方法爲A< i n t > m;在類A後面跟上一個<>尖括號並在裏面填上相應的類型,這樣的話類A中凡是用到模板形參的地方都會被int 所代替。當類模板有兩個模板形參時創建對象的方法爲A < int, double > m;類型之間用逗號隔開。

1.2.4
對於類模板,模板形參的類型必須在類名後的尖括號中明確指定。比如A< 2 > m;用這種方法把模板形參設置爲int是錯誤的(編譯錯誤:error C2079: ‘a’ uses undefined class ‘A< int >’),類模板形參不存在實參推演的問題。也就是說不能把整型值2推演爲int 型傳遞給模板形參。要把類模板形參調置爲int 型必須這樣指定A< int > m。

1.2.5
在類模板外部定義成員函數的方法爲:

    template<模板形參列表> 函數返回類型 類名<模板形參名>::函數名(參數列表){函數體},

比如有兩個模板形參T1,T2的類A中含有一個void h()函數,則定義該函數的語法爲:

  template<class T1,class T2> void A<T1,T2>::h(){}

注意:當在類外面定義類的成員時template後面的模板形參應與要定義的類的模板形參一致。

1.2.6
再次提醒注意:模板的聲明或定義只能在全局,命名空間或類範圍內進行。即不能在局部範圍,函數內進行,比如不能在main函數中聲明或定義一個模板。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章