搜尋

C++ 模板

Dec 13, 2016 pm 02:31 PM
template

函式模板

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

上述定義了一個類別模板​​--棧,這個棧很簡單,只是為了說明類別模板如何使用而已,最多只能支援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.h
template <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.cpp
template <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,在使用原來的swap函數,執行tmpT = t1要拷貝t1的全部元素,佔用大量內存,造成性能下降,於是我們系統通過vector.swap函數解決這個問題,代碼如下:

//method.h
template<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的swap程式碼還是比較局限,如果要用模板專門化解決所有vector的swap,該如何做呢,只需要把下面程式碼

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

改為

就可以了,其他程式碼不變。

類模板專門化

 請看下面compare代碼:

template<class V> void swap(std::vector<V>& t1, std::vector<V>& t2) {
    t1.swap(t2);
}
//compare.h
template <class T>
 class compare
 {
  public:
  bool equal(T t1, T t2)
  {
       return t1 == t2;
  }
};

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

#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;
 }

main.cpp檔案不變,此程式碼可以正常運作。

模板類型轉換

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

//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;
    }
};

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

reee

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

//shape.h
class 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;
}
//statck.h
template <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"

這樣,Stack或Stack就可以自動轉換為Stack或Stack,如果轉換的型別是Stack到Stack,編譯器會報錯。

🎜其他🎜🎜一個類別沒有模板參數,但是成員函數有模板參數,是可行的,代碼如下:🎜
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;
}
🎜甚至可以把Util的equal聲明為static,代碼如下:🎜
//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;
}
🎜🎜🎜
陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
C#.NET的未來:趨勢和機遇C#.NET的未來:趨勢和機遇Apr 29, 2025 am 12:02 AM

C#.NET的未來趨勢主要集中在雲計算、微服務、AI和機器學習集成以及跨平台開發三個方面。 1)雲計算和微服務:C#.NET通過Azure平台優化雲環境表現,支持構建高效微服務架構。 2)AI和機器學習集成:借助ML.NET庫,C#開發者可在應用中嵌入機器學習模型,推動智能化應用發展。 3)跨平台開發:通過.NETCore和.NET5 ,C#應用可在Windows、Linux和macOS上運行,擴展部署範圍。

C#.NET開發今天:趨勢和最佳實踐C#.NET開發今天:趨勢和最佳實踐Apr 28, 2025 am 12:25 AM

C#.NET開發的最新動態和最佳實踐包括:1.異步編程提高應用響應性,使用async和await關鍵字簡化非阻塞代碼;2.LINQ提供強大查詢功能,通過延遲執行和表達式樹高效操作數據;3.性能優化建議包括使用異步編程、優化LINQ查詢、合理管理內存、提升代碼可讀性和維護性、以及編寫單元測試。

C#.NET:使用.NET生態系統構建應用程序C#.NET:使用.NET生態系統構建應用程序Apr 27, 2025 am 12:12 AM

如何利用.NET構建應用?使用.NET構建應用可以通過以下步驟實現:1)了解.NET基礎知識,包括C#語言和跨平台開發支持;2)學習核心概念,如.NET生態系統的組件和工作原理;3)掌握基本和高級用法,從簡單控制台應用到復雜的WebAPI和數據庫操作;4)熟悉常見錯誤與調試技巧,如配置和數據庫連接問題;5)應用性能優化與最佳實踐,如異步編程和緩存。

C#作為多功能.NET語言:應用程序和示例C#作為多功能.NET語言:應用程序和示例Apr 26, 2025 am 12:26 AM

C#在企業級應用、遊戲開發、移動應用和Web開發中均有廣泛應用。 1)在企業級應用中,C#常用於ASP.NETCore開發WebAPI。 2)在遊戲開發中,C#與Unity引擎結合,實現角色控制等功能。 3)C#支持多態性和異步編程,提高代碼靈活性和應用性能。

C#.NET用於網絡,桌面和移動開發C#.NET用於網絡,桌面和移動開發Apr 25, 2025 am 12:01 AM

C#和.NET適用於Web、桌面和移動開發。 1)在Web開發中,ASP.NETCore支持跨平台開發。 2)桌面開發使用WPF和WinForms,適用於不同需求。 3)移動開發通過Xamarin實現跨平台應用。

C#.NET生態系統:框架,庫和工具C#.NET生態系統:框架,庫和工具Apr 24, 2025 am 12:02 AM

C#.NET生態系統提供了豐富的框架和庫,幫助開發者高效構建應用。 1.ASP.NETCore用於構建高性能Web應用,2.EntityFrameworkCore用於數據庫操作。通過理解這些工具的使用和最佳實踐,開發者可以提高應用的質量和性能。

將C#.NET應用程序部署到Azure/AWS:逐步指南將C#.NET應用程序部署到Azure/AWS:逐步指南Apr 23, 2025 am 12:06 AM

如何將C#.NET應用部署到Azure或AWS?答案是使用AzureAppService和AWSElasticBeanstalk。 1.在Azure上,使用AzureAppService和AzurePipelines自動化部署。 2.在AWS上,使用AmazonElasticBeanstalk和AWSLambda實現部署和無服務器計算。

C#.NET:強大的編程語言簡介C#.NET:強大的編程語言簡介Apr 22, 2025 am 12:04 AM

C#和.NET的結合為開發者提供了強大的編程環境。 1)C#支持多態性和異步編程,2).NET提供跨平台能力和並發處理機制,這使得它們在桌面、Web和移動應用開發中廣泛應用。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具