與函數模板相似地(C++模板詳解(一):函數模板的概念和特性) ,類也能夠被一種或多種類型參數化。例如,容器類就是一個具備這種特性的典型例子,它一般被用於管理某種特定類型的元素。只要使用類模板,咱們就能夠實現容器類,而不須要肯定容器中元素的類型。html
在這篇博文中,咱們使用Stack
做爲類模板的例子。函數
#include <vector> #include <deque> #include <stdexcept> template<typename T> class Stack { std::vector<T> elems; // 存儲元素的容器。 public: void push(const T& value); // 將元素壓入棧中。 void pop(); // 將棧頂元素彈出棧。 T top() const; // 查看棧頂元素的副本。 bool empty() const { // 檢查棧是否爲空。 return elems.empty(); } }; template<typename T> void Stack<T>::push(const T& value) { elems.push_back(value); } template<typename T> void Stack<T>::pop() { if (elems.empty()) { throw std::out_of_range("Stack<>::pop(): empty stack"); } elems.pop_back(); } template<typename T> T Stack<T>::top() const { if (elems.empty()) { throw std::out_of_range("Stack<>::pop(): empty stack"); } return elems.back(); }
如上所示,類模板的聲明和函數模板的聲明很類似:在聲明以前,咱們先聲明參數類型的標識符spa
template<typename /*class*/ T> class Stack { //... };
固然,也可使用關鍵字class
來代替typename
。在類模板的內部,類型T
能夠像其它的類型同樣,用於聲明成員變量和成員函數。在這個例子中,類的類型是Stack<T>
,其中T
是模板參數。所以,<font color="red"><strong>當在聲明中須要使用該類的類型時,咱們必需要使用Stack<T>
</strong></font>。例如,若是要聲明本身實現的拷貝構造函數和賦值運算符,那就應該這樣來編寫:code
template<typename T> class Stack { //... Stack(const Stack<T>& other); // 這裏的構造函數名稱須要與類名相同(Stack) Stack<T>& operator=(const Stack<T>& other); // 這裏的拷貝構造函數須要使用類的類型(Stack<T>) //... };
然而, 當須要使用類名而不是類的類型時,就應該只用Stack
。例如,當指定類的名稱,或是須要編寫構造函數、析構函數時,就須要使用Stack
。htm
爲了定義類模板的成員函數,咱們必需要指定該成員函數是一個函數模板(使用template<typename T>
),並且還須要使用這個類模板的完整類型限定運算符Stack<T>::
。所以,成員函數push
的完整定義以下:blog
template<typename T> void Stack<T>::push(const T& value) { elems.push_back(value); }
其它成員函數的實現也是相似的;和普通類定義相同,徹底也能夠將成員函數的實現內聯地寫在類中,例如:get
template<typename T> class Stack { std::vector<T> elems; // 存儲元素的容器。 public: // ... bool empty() const { // 檢查棧是否爲空。 return elems.empty(); } };
參見以下的main
函數代碼:string
int main() { try { Stack<int> intStack; Stack<std::string> stringStack; // 使用int棧 intStack.push(7); std::cout << intStack.top() << std::endl; // 使用string棧 stringStack.push("hello"); std::cout << stringStack.top() << std::endl; stringStack.pop(); stringStack.pop(); } catch (std::exception &ex) { std::cerr << "Exception: " << ex.what() << std::endl; return EXIT_FAILURE; } return 0; }
<font color="red"><strong>注意:</strong></font><strong>只有那些被調用了的成員函數,纔會產生這些函數的實例化代碼。</strong>io
因此,針對這個類模板,缺省的構造函數、push
、top
方法都針對int
、std::string
進行了實例化。然而, pop
方法只提供了std::string
的實例化。這樣作的好處是:模板
另外一方面,若是類中含有靜態成員,那麼用來實例化的每種類型,都會實例化這些靜態成員。
原文出處:https://www.cnblogs.com/rosefinch/p/12294600.html