與函式模板類似地(C++模板詳解(一):函式模板的概念和特性) ,類也可以被一種或多種型別引數化,例如,容器類就是一個具有這種特性的典型例子,它通常被用于管理某種特定型別的元素,只要使用類模板,我們就可以實作容器類,而不需要確定容器中元素的型別,
一、類模板的實作
在這篇博文中,我們使用Stack作為類模板的例子,
(1.1) 類模板的宣告
#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();
}
如上所示,類模板的宣告和函式模板的宣告很相似:在宣告之前,我們先宣告引數型別的識別符號
template<typename /*class*/ T>
class Stack
{
//...
};
當然,也可以使用關鍵字class來代替typename,在類模板的內部,型別T可以像其它的型別一樣,用于宣告成員變數和成員函式,在這個例子中,類的型別是Stack<T>,其中T是模板引數,因此,當在宣告中需要使用該類的型別時,我們必須要使用Stack<T>,例如,如果要宣告自己實作的拷貝建構式和賦值運算子,那就應該這樣來撰寫:
template<typename T>
class Stack
{
//...
Stack(const Stack<T>& other); // 這里的建構式名稱需要與類名相同(Stack)
Stack<T>& operator=(const Stack<T>& other); // 這里的拷貝建構式需要使用類的型別(Stack<T>)
//...
};
然而, 當需要使用類名而不是類的型別時,就應該只用Stack,例如,當指定類的名稱,或是需要撰寫建構式、解構式時,就需要使用Stack,
(1.2) 類模板的實作
為了定義類模板的成員函式,我們必須要指定該成員函式是一個函式模板(使用template<typename T>),而且還需要使用這個類模板的完整型別限定運算子Stack<T>::,因此,成員函式push的完整定義如下:
template<typename T>
void Stack<T>::push(const T& value)
{
elems.push_back(value);
}
其它成員函式的實作也是類似的;和普通類定義相同,完全也可以將成員函式的實作行內地寫在類中,例如:
template<typename T>
class Stack
{
std::vector<T> elems; // 存盤元素的容器,
public:
// ...
bool empty() const { // 檢查堆疊是否為空,
return elems.empty();
}
};
二、類模板的使用
參見如下的main函式代碼:
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;
}
注意:只有那些被呼叫了的成員函式,才會產生這些函式的實體化代碼,
所以,針對這個類模板,預設的建構式、push、top方法都針對int、std::string進行了實體化,然而, pop方法只提供了std::string的實體化,這樣做的好處是:
- 可以節省時間和空間,
- 對于那些未能提供所有成員函式中所有操作的型別,也可以使用該型別來實體化類模板,
另一方面,如果類中含有靜態成員,那么用來實體化的每種型別,都會實體化這些靜態成員,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/64984.html
標籤:C++
上一篇:C++對于C故有問題的改進
