C++ Template

來源:互聯網
上載者:User
函數模板

在c++入門中,很多人會接觸swap(int&, int&)這樣的函數類似代碼如下:

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

但是如果是要支援long,string,自訂class的swap函數,代碼和上述代碼差不多,只是類型不同,這個時候就是我們定義swap的函數模板,就可以複用不同類型的swap函數代碼,函數模板的聲明形式如下:

template <class identifier> function_declaration;template <typename identifier> function_declaration;

swap函數模板的聲明和定義代碼如下:

//method.htemplate<typename T> void swap(T& t1, T& t2);#include "method.cpp"
//method.cpptemplate<typename  T> void swap(T& t1, T& t2) {    T tmpT;    tmpT = t1;    t1 = t2;    t2 = tmpT;}

上述是模板的聲明和定義了,那模板如何執行個體化呢,模板的執行個體化是編譯器做的事情,與程式員無關,那麼上述模板如何使用呢,代碼如下:

//main.cpp#include <stdio.h>#include "method.h"int main() {    //模板方法     int num1 = 1, num2 = 2;    swap<int>(num1, num2);    printf("num1:%d, num2:%d\n", num1, num2);      return 0;}

這裡使用swap函數,必須包含swap的定義,否則編譯會出錯,這個和一般的函數使用不一樣。所以必須在method.h檔案的最後一行加入#include "method.cpp"。

類模板

考慮我們寫一個簡單的棧的類,這個棧可以支援int類型,long類型,string類型等等,不利用類模板,我們就要寫三個以上的stack類,其中代碼基本一樣,通過類模板,我們可以定義一個簡單的棧模板,再根據需要執行個體化為int棧,long棧,string棧。

//statck.htemplate <class T> class Stack {    public:        Stack();        ~Stack();        void push(T t);        T pop();        bool isEmpty();    private:        T *m_pT;                int m_maxSize;        int m_size;};#include "stack.cpp"
//stack.cpptemplate <class  T>  Stack<T>::Stack(){   m_maxSize = 100;         m_size = 0;   m_pT = new T[m_maxSize];}template <class T>  Stack<T>::~Stack() {   delete [] m_pT ;}        template <class T> void Stack<T>::push(T t) {    m_size++;    m_pT[m_size - 1] = t;    }template <class T> T Stack<T>::pop() {    T t = m_pT[m_size - 1];    m_size--;    return t;}template <class T> bool Stack<T>::isEmpty() {    return m_size == 0;}

上述定義了一個類模板--棧,這個棧很簡單,只是為了說明類模板如何使用而已,最多隻能支援100個元素入棧,使用樣本如下:

//main.cpp#include <stdio.h>#include "stack.h"int main() {    Stack<int> intStack;    intStack.push(1);    intStack.push(2);    intStack.push(3);        while (!intStack.isEmpty()) {        printf("num:%d\n", intStack.pop());    }    return 0;}

模板參數
模板可以有型別參數,也可以有常規的型別參數int,也可以有預設範本參數,例如

template<class T, T def_val> class Stack{...}

上述類模板的棧有一個限制,就是最多隻能支援100個元素,我們可以使用模板參數配置這個棧的最大元素數,如果不配置,就設定預設最大值為100,代碼如下:

//statck.htemplate <class T,int maxsize = 100> class Stack {    public:        Stack();        ~Stack();        void push(T t);        T pop();        bool isEmpty();    private:        T *m_pT;                int m_maxSize;        int m_size;};#include "stack.cpp"
//stack.cpptemplate <class T,int maxsize> Stack<T, maxsize>::Stack(){   m_maxSize = maxsize;         m_size = 0;   m_pT = new T[m_maxSize];}template <class T,int maxsize>  Stack<T, maxsize>::~Stack() {   delete [] m_pT ;}        template <class T,int maxsize> void Stack<T, maxsize>::push(T t) {    m_size++;    m_pT[m_size - 1] = t;    }template <class T,int maxsize> T Stack<T, maxsize>::pop() {    T t = m_pT[m_size - 1];    m_size--;    return t;}template <class T,int maxsize> bool Stack<T, maxsize>::isEmpty() {    return m_size == 0;}

使用樣本如下:

//main.cpp#include <stdio.h>#include "stack.h"int main() {    int maxsize = 1024;    Stack<int,1024> intStack;    for (int i = 0; i < maxsize; i++) {        intStack.push(i);    }    while (!intStack.isEmpty()) {        printf("num:%d\n", intStack.pop());    }    return 0;}

模板專門化

當我們要定義模板的不同實現,我們可以使用模板的專門化。例如我們定義的stack類模板,如果是char*類型的棧,我們希望可以複製char的所有資料到stack類中,因為只是儲存char指標,char指標指向的記憶體有可能會失效,stack彈出的堆棧元素char指標,指向的記憶體可能已經無效了。還有我們定義的swap函數模板,在vector或者list等容器類型時,如果容器儲存的對象很大,會佔用大量記憶體,效能下降,因為要產生一個臨時的大對象儲存a,這些都需要模板的專門化才能解決。

函數模板專門化

假設我們swap函數要處理一個情況,我們有兩個很多元素的vector<int>,在使用原來的swap函數,執行tmpT = t1要拷貝t1的全部元素,佔用大量記憶體,造成效能下降,於是我們系統通過vector.swap函數解決這個問題,代碼如下:

//method.htemplate<class T> void swap(T& t1, T& t2);#include "method.cpp"
#include <vector>using namespace std;template<class T> void swap(T& t1, T& t2) {    T tmpT;    tmpT = t1;    t1 = t2;    t2 = tmpT;}template<> void swap(std::vector<int>& t1, std::vector<int>& t2) {    t1.swap(t2);}

template<>首碼表示這是一個專門化,描述時不用模板參數,使用樣本如下:

//main.cpp#include <stdio.h>#include <vector>#include <string>#include "method.h"int main() {    using namespace std;    //模板方法     string str1 = "1", str2 = "2";    swap(str1, str2);    printf("str1:%s, str2:%s\n", str1.c_str(), str2.c_str());          vector<int> v1, v2;    v1.push_back(1);    v2.push_back(2);    swap(v1, v2);    for (int i = 0; i < v1.size(); i++) {        printf("v1[%d]:%d\n", i, v1[i]);    }    for (int i = 0; i < v2.size(); i++) {        printf("v2[%d]:%d\n", i, v2[i]);    }    return 0;}

vector<int>的swap代碼還是比較局限,如果要用模板專門化解決所有vector的swap,該如何做呢,只需要把下面代碼

template<> void swap(std::vector<int>& t1, std::vector<int>& t2) {    t1.swap(t2);}

改為

template<class V> void swap(std::vector<V>& t1, std::vector<V>& t2) {    t1.swap(t2);}

就可以了,其他代碼不變。

類模板專門化

請看下面compare代碼:

//compare.htemplate <class T> class compare {  public:  bool equal(T t1, T t2)  {       return t1 == t2;  }};
#include <iostream>#include "compare.h" int main() {  using namespace std;  char str1[] = "Hello";  char str2[] = "Hello";  compare<int> c1;  compare<char *> c2;     cout << c1.equal(1, 1) << endl;        //比較兩個int類型的參數  cout << c2.equal(str1, str2) << endl;   //比較兩個char *類型的參數  return 0; }

在比較兩個整數,compare的equal方法是正確的,但是compare的模板參數是char*時,這個模板就不能工作了,於是修改如下:

//compare.h#include <string.h>template <class T> class compare {  public:  bool equal(T t1, T t2)  {       return t1 == t2;  }};   template<>class compare<char *>  {public:    bool equal(char* t1, char* t2)    {        return strcmp(t1, t2) == 0;    }};

main.cpp檔案不變,此代碼可以正常工作。

模板類型轉換

還記得我們自訂的Stack模板嗎,在我們的程式中,假設我們定義了Shape和Circle類,代碼如下:

//shape.hclass Shape {};class Circle : public Shape {};


然後我們希望可以這麼使用:

//main.cpp#include <stdio.h>#include "stack.h"#include "shape.h"int main() {    Stack<Circle*> pcircleStack;    Stack<Shape*> pshapeStack;    pcircleStack.push(new Circle);    pshapeStack = pcircleStack;    return 0;}

這裡是無法編譯的,因為Stack<Shape*>不是Stack<Circle*>的父類,然而我們卻希望代碼可以這麼工作,那我們就要定義轉換運算子了,Stack代碼如下:

//statck.htemplate <class T> class Stack {    public:        Stack();        ~Stack();        void push(T t);        T pop();        bool isEmpty();        template<class T2>  operator Stack<T2>();    private:        T *m_pT;                int m_maxSize;        int m_size;};#include "stack.cpp"
template <class  T>  Stack<T>::Stack(){   m_maxSize = 100;         m_size = 0;   m_pT = new T[m_maxSize];}template <class T>  Stack<T>::~Stack() {   delete [] m_pT ;}        template <class T> void Stack<T>::push(T t) {    m_size++;    m_pT[m_size - 1] = t;    }template <class T> T Stack<T>::pop() {    T t = m_pT[m_size - 1];    m_size--;    return t;}template <class T> bool Stack<T>::isEmpty() {    return m_size == 0;}template <class T> template <class T2>  Stack<T>::operator Stack<T2>() {    Stack<T2> StackT2;    for (int i = 0; i < m_size; i++) {        StackT2.push((T2)m_pT[m_size - 1]);    }    return StackT2;}
//main.cpp#include <stdio.h>#include "stack.h"#include "shape.h"int main() {    Stack<Circle*> pcircleStack;    Stack<Shape*> pshapeStack;    pcircleStack.push(new Circle);    pshapeStack = pcircleStack;    return 0;}

這樣,Stack<Circle>或者Stack<Circle*>就可以自動轉換為Stack<Shape>或者Stack<Shape*>,如果轉換的類型是Stack<int>到Stack<Shape>,編譯器會報錯。

其他

一個類沒有模板參數,但是成員函數有模板參數,是可行的,代碼如下:

class Util {    public:        template <class T> bool equal(T t1, T t2) {            return t1 == t2;        }};int main() {    Util util;    int a = 1, b = 2;    util.equal<int>(1, 2);    return 0;}

甚至可以把Util的equal聲明為static,代碼如下:

class Util {    public:         template <class T> static bool equal(T t1, T t2) {            return t1 == t2;        }};int main() {    int a = 1, b = 2;    Util::equal<int>(1, 2);    return 0;}
  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.