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

C++類模板(Class Template)

編輯:C++基礎知識
C++ 除了支持函數模板,還支持類模板(Class Template)。函數模板中定義的類型參數可以用在函數聲明和函數定義中,類模板中定義的類型參數可以用在類聲明和類實現中。類模板的目的同樣是將數據的類型參數化。

聲明類模板的語法為:

template<typename 類型參數1 , typename 類型參數2 , …> class 類名{
    //TODO:
};

類模板和函數模板都是以 template 開頭(當然也可以使用 class,目前來講它們沒有任何區別),後跟類型參數;類型參數不能為空,多個類型參數用逗號隔開。

一但聲明了類模板,就可以將類型參數用於類的成員函數和成員變量了。換句話說,原來使用 int、float、char 等內置類型的地方,都可以用類型參數來代替。

假如我們現在要定義一個類來表示坐標,要求坐標的數據類型可以是整數、小數和字符串,例如:
  • x = 10、y = 10
  • x = 12.88、y = 129.65
  • x = "東京180度"、y = "北緯210度"

這個時候就可以使用類模板,請看下面的代碼:
template<typename T1, typename T2>  //這裡不能有分號
class Point{
public:
    Point(T1 x, T2 y): m_x(x), m_y(y){ }
public:
    T1 getX() const;  //獲取x坐標
    void setX(T1 x);  //設置x坐標
    T2 getY() const;  //獲取y坐標
    void setY(T2 y);  //設置y坐標
private:
    T1 m_x;  //x坐標
    T2 m_y;  //y坐標
};
x 坐標和 y 坐標的數據類型不確定,借助類模板可以將數據類型參數化,這樣就不必定義多個類了。
注意:模板頭和類頭是一個整體,可以換行,但是中間不能有分號。
上面的代碼僅僅是類的聲明,我們還需要在類外定義成員函數。在類外定義成員函數時仍然需要帶上模板頭,格式為:

template<typename 類型參數1 , typename 類型參數2 , …>
返回值類型 類名<類型參數1 , 類型參數2, ...>::函數名(形參列表){
    //TODO:
}

第一行是模板頭,第二行是函數頭,它們可以合並到一行,不過為了讓代碼格式更加清晰,一般是將它們分成兩行。

下面就對 Point 類的成員函數進行定義:
template<typename T1, typename T2>  //模板頭
T1 Point<T1, T2>::getX() const /*函數頭*/ {
    return m_x;
}

template<typename T1, typename T2>
void Point<T1, T2>::setX(T1 x){
    m_x = x;
}

template<typename T1, typename T2>
T2 Point<T1, T2>::getY() const{
    return m_y;
}

template<typename T1, typename T2>
void Point<T1, T2>::setY(T2 y){
    m_y = y;
}
請讀者仔細觀察代碼,除了 template 關鍵字後面要指明類型參數,類名 Point 後面也要帶上類型參數,只是不加 typename 關鍵字了。另外需要注意的是,在類外定義成員函數時,template 後面的類型參數要和類聲明時的一致。

使用類模板創建對象

上面的兩段代碼完成了類的定義,接下來就可以使用該類創建對象了。使用類模板創建對象時,需要指明具體的數據類型。請看下面的代碼:
Point<int, int> p1(10, 20);
Point<int, float> p2(10, 15.5);
Point<float, char*> p3(12.4, "東京180度");
與函數模板不同的是,類模板在實例化時必須顯式地指明數據類型,編譯器不能根據給定的數據推演出數據類型。

除了對象變量,我們也可以使用對象指針的方式來實例化:
Point<float, float> *p1 = new Point<float, float>(10.6, 109.3);
Point<char*, char*> *p = new Point<char*, char*>("東京180度", "北緯210度");
需要注意的是,賦值號兩邊都要指明具體的數據類型,且要保持一致。下面的寫法是錯誤的:
//賦值號兩邊的數據類型不一致
Point<float, float> *p = new Point<float, int>(10.6, 109);
//賦值號右邊沒有指明數據類型
Point<float, float> *p = new Point(10.6, 109);

綜合示例

將上面的類定義和類實例化的代碼整合起來,構成一個完整的示例,如下所示:
#include <iostream>
using namespace std;

template<class T1, class T2>  //這裡不能有分號
class Point{
public:
    Point(T1 x, T2 y): m_x(x), m_y(y){ }
public:
    T1 getX() const;  //獲取x坐標
    void setX(T1 x);  //設置x坐標
    T2 getY() const;  //獲取y坐標
    void setY(T2 y);  //設置y坐標
private:
    T1 m_x;  //x坐標
    T2 m_y;  //y坐標
};

template<class T1, class T2>  //模板頭
T1 Point<T1, T2>::getX() const /*函數頭*/ {
    return m_x;
}

template<class T1, class T2>
void Point<T1, T2>::setX(T1 x){
    m_x = x;
}

template<class T1, class T2>
T2 Point<T1, T2>::getY() const{
    return m_y;
}

template<class T1, class T2>
void Point<T1, T2>::setY(T2 y){
    m_y = y;
}

int main(){
    Point<int, int> p1(10, 20);
    cout<<"x="<<p1.getX()<<", y="<<p1.getY()<<endl;
 
    Point<int, char*> p2(10, "東京180度");
    cout<<"x="<<p2.getX()<<", y="<<p2.getY()<<endl;
 
    Point<char*, char*> *p3 = new Point<char*, char*>("東京180度", "北緯210度");
    cout<<"x="<<p3->getX()<<", y="<<p3->getY()<<endl;

    return 0;
}
運行結果:
x=10, y=20
x=10, y=東京180度
x=東京180度, y=北緯210度

在定義類型參數時我們使用了 class,而不是 typename,這樣做的目的是讓讀者對兩種寫法都熟悉。
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved