HOME ABOUT CONTACT

C/C++教學: 第三十一課 - 樣板(Template)

Rain December 30, 2024
Outline

1. 簡介

2. 函式樣板(Function Template)

3. 類別樣板(Class Template)

簡介top

樣板(Template)最主要的目的是作為所有資料類型的代名詞,讓設計架構可以更精簡,例如簡化多載函式或眾多類別的延伸介面,這兩者又可分別稱為函式樣板和類別樣板。

函式樣板top

當函式希望設計成可以支援多種資料型態的輸入和回傳時,多載函式雖然可以達成,但種類一多時也會造成很冗長且相同的操作內容的程式碼,這時候樣板函式就可以派上用場,我們先來看看它的語法


template< class T >
T func(T a) {
    // do something...
}
                        

首先免不了我們需要一個 template 的關鍵字,隨後附帶一對角括號,角括號內用 class 用來定義 T,意思是 T 代表了所有的資料類型,你可以把它理解為一個代名詞。

class 關鍵字和我們前面介紹的類別(Class)是不同物,初學者可能容易混淆。定義樣板時,class 會去認 template 關鍵字和是否在角括號內。

然後寫上函式的定義,這時候所有在定義輸入參數的資料類型,以及返回值的資料型態,全都可以用 T 來表示,這樣就可以完成處理眾多資料類型的樣板函式。

類別樣板top

類別樣板常作為多種類別的延伸介面,理解為附加功能可能會更為貼切。它和父類別的概念有點相反,父類別是起始點,類別樣板通常是中繼點或終點,概念圖如下:

運用 template 關鍵字,我們可以將多種類別轉變為統一的代名,然後再由樣板類別去做延伸。承上圖架構舉例,我們有一個 Car 的父類別作為起點,它的子類別延伸出日本車和歐系車,當我們特別想對日本車、歐系車或 SUV 車種各別做額外的延伸時,就可以運用樣板類別,如下例:


class Car {
public:
    ...
private:
    ...
};

class Lexus_NX_350 : public Car {
public:
    ...
private:
    ...
};

class Toyota_CRV : public Car {
public:
    ...
private:
    ...
};

template< class T >
class SUV {
    ...
}
                        

上例中,我們設計了一套日本車的類別,然後再針對 SUV 車型做一個類別樣板,實際程式碼範例如下:


class Car {
public:
    string info() {
        return string("This is a car class.");
    }
};
                                
class Lexus_NX_350 : public Car {
public:
    string info() {
        return string("Lexus NX 350.");
    }
};
                                
class Toyota_CRV : public Car {
public:
    string info() {
        return string("Toyota CRV.");
    }
};
                                
template< class T >
class SUV {
public:
    SUV(T *t) {
        m_original_class = t;
    }
    void extended_info() {
        cout << "This is SUV: " << m_original_class->info() << endl;
    }
private:
    T* m_original_class;
};

int main()
{
	Lexus_NX_350 lnx350;
	Toyota_CRV crv;
	cout << lnx350.info() << endl;
	cout << crv.info() << endl;
	SUV< Lexus_NX_350 > suv1(&lnx350);
	SUV< Toyota_CRV > suv2(&crv);
	suv1.extended_info();
	suv2.extended_info();
}
                        

上例中,我們將日本車的 SUV 車型做一個簡單的延伸,讓 info() 函式可以附加 SUV 標示的字詞。我們在 SUV 建構式中定義了參數為一個代名詞 T,用來接收所有類型的物件或變數,並且用一個指標成員去指向該物件或變數,你會注意到這個指標也是用代名詞 T 來宣告。

當成員指標指向原形類別之後,我們就可以用類別樣板中的方法去做延伸,如同 extended_info() 函式。那麼在延伸的方法中,程式是什麼時候知道有一個方法是叫 info() 呢? 答案在編譯時期得知的,若所引用的定義域中沒有這樣的方法,或是類型不正確時,編譯就會報錯誤訊息。


Last updated:

Related Article List

  1. C/C++教學: 第二十九課 - 類別(Class)的多形(Polymorphism)
  2. C/C++教學: 第三十課 - 類別(Class)的建構(Constructor)和解構(Destructor)