1. 程式人生 > >C++模板template用法總結

C++模板template用法總結

引言

模板(Template)指C++程式設計設計語言中採用型別作為引數的程式設計,支援通用程式設計。C++ 的標準庫提供許多有用的函式大多結合了模板的觀念,如STL以及IO Stream。

函式模板

在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.cpp
template<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;
}

相關推薦

C++模板template用法總結

引言 模板(Template)指C++程式設計設計語言中採用型別作為引數的程式設計,支援通用程式設計。C++ 的標準庫提供許多有用的函式大多結合了模板的觀念,如STL以及IO Stream。 函式模板 在c++入門中,很多人會接觸swap(int&, int

c/c++中const用法總結

沒有 pan 分配 值類型 變量初始化 _id 多少 部分 參數 1、修飾常量時:   const int temp1; //temp1為常量,不可變   int const temp2; //temp2為常量,不可變 2、修飾指針時:   主要看const在*的前後,

C/C++:static用法總結

.sh pre 值類型 定義和使用 靜態 public out pan -1 前言:static是C/C++中一個很重要的關鍵字,最近閱讀了很多博客和資料,遂在此對自己的學習筆記進行簡單的總結並發表在這裏 一、C語言中的static ? 靜態全局變量:在全局變量之前加

C++中STL用法總結【轉】

(轉自:https://blog.csdn.net/piaoxuezhong/article/details/54348787?utm_source=blogxgwz8) 1.1 什麼是STL? STL(Standard Template Library),即標準模板庫,是一個具有工業強度的

C/C++ assert()函式用法總結

轉自:https://www.cnblogs.com/lvchaoshun/p/7816288.html   assert巨集的原型定義在<assert.h>中,其作用是如果它的條件返回錯誤,則終止程式執行。 原型定義: #include <assert.

C++ vector常見用法總結

此文為個人學習備份,點選這裡訪問原文。 vector是一個動態的序列容器,相當於一個size可變的陣列。     相比於陣列,vector會消耗更多的記憶體以有效的動態增長。而相比於其他動態序列容器(deques, lists and forward_lists

C++中CONST用法總結

1、修飾常量時: ? 1 2 const int temp1; //temp1為常量,不可變 int const temp2; //temp2為常量,不可變 2、修飾指標時:   主要看const在*的前後,

c語言const用法總結

這裡講的是c中的const不是cpp中的 int const a 等價於 int const b char * const p 表示指標變數p中的地址不可被修改 const char *p  表示指標p指向的記憶體空間不可被修改 const chat * co

C++模板Template的使用,精簡詳解,秒懂。

    為了能夠完整地描述模板的建立和具體使用,以下會有完善的測試,請大家耐心看下去,基本可以看得懂,即學即用。// CPP面向物件.cpp: 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <iostream> u

C++中STL用法總結

函式庫對資料型別的選擇對其可重用性起著至關重要的作用。舉例來說,一個求方根的函式,在使用浮點數作為其引數型別的情況下的可重用性肯定比使用整型作為它的引數類性要高。而C++通過模板的機制允許推遲對某些型別的選擇,直到真正想使用模板或者說對模板進行特化的時候,STL就利用了這一點提供了相當多的有用演算法。它是在一

【轉】C++中static用法總結

地址:https://www.cnblogs.com/qiaoconglovelife/p/5323086.html 1.用於區域性變數 C++中區域性變數有三種: (1)auto:此關鍵詞常常省略。auto type a 常常簡寫為type a。 如:int a=auto int

c/c++中static用法總結

static的作用主要有兩種: 第一個作用是限定作用域;第二個作用是保持變數內容持久化; c語言中static的用法: 1、全域性靜態變數:   用法:在全域性變數前加上關鍵字static,全域性變數就定義成一個全域性靜態變數。 static int temp;   記憶體中的位置:靜態儲存區,在整個程式執行

C# StackExchange.Redis 用法總結

安裝 StackExchange.Redis 在 NuGet 中搜索 StackExchange.Redis 和 Newtonsoft.Json,直接點選按鈕安裝即可。 StackExchange.Redis 是 C# 操作 Redis 資料庫的客戶端。 Newtonsoft.Json 用來序列化 Jo

C++ vector的用法總結

vector是可變長度的陣列,需要標頭檔案#include<vector> 1. 初始化 // 建構函式 vector<int> abc(10); //10個0 vector<int> def(10,1); //10個1 // 陣列地

c++中__declspec用法總結

“__declspec”是Microsoft c++中專用的關鍵字,它配合著一些屬性可以對標準C++進行擴充。這些屬性有:align、allocate、deprecated、 dllexport、dllimport、 naked、noinline、noreturn、nothr

C++中 模板Template的使用

ddc 說明 hid javascrip tro 返回 數據 ret text 1、在c++Template中非常多地方都用到了typename與class這兩個關鍵字,並且好像能夠替換,是不是這兩個關鍵字全然一樣呢? 答:class用於定義類,在模板

C數據結構排序算法——直接插入排序法用法總結(轉http://blog.csdn.net/lg1259156776/)

所有 可能 app 必須 操作 itl 直接排序 works 技術分享 聲明:引用請註明出處http://blog.csdn.net/lg1259156776/ 排序相關的的基本概念 排序:將一組雜亂無章的數據按一定的規律順次排列起來。 數據表( data list)

C數據結構排序算法——希爾排序法用法總結(轉http://www.cnblogs.com/skywang12345/p/3597597.html)

spa 一半 pub nbsp 時間復雜度 每一個 ati 數組長度 插入排序算法 希爾排序介紹 希爾排序(Shell Sort)是插入排序的一種,它是針對直接插入排序算法的改進。該方法又稱縮小增量排序,因DL.Shell於1959年提出而得名。 希爾排序實質上是一種分組插

標準C++中的string類的用法總結

也有 www. empty capacity 技術 第一個 stream 一次 jpg 相信使用過MFC編程的朋友對CString這個類的印象應該非常深刻吧?的確,MFC中的CString類使用起來真的非常的方便好用。但是如果離開了MFC框架,還有沒有這樣使用起來非常方便

標準C++中的string類的用法總結(轉)

spa 大小 它的 world 包括 文本 語法 ner append() 轉自:http://www.cnblogs.com/xFreedom/archive/2011/05/16/2048037.html 相信使用過MFC編程的朋友對CString這個類的印象應該