C++ Templates (2.1 類模板Stack的實現 Implementation of Class Template Stack)

返回完整目錄html

2.1 類模板Stack的實現 Implementation of Class Template Stack

正如函數模板,能夠以下方式在一個頭文件中聲明和定義類Stack<>安全

// basics/stack1.hpp

#include <vector>
#include <cassert>

template <typename T>
class Stack
{
private:
      std::vector<T> elems;      //元素

public:
      void push(T const& elem);      //壓入元素
      void pop();      // 彈出元素
      T const& top() const;      //返回頂上的元素
      bool empty()      //返回棧stack是否爲空
      {
            return elems.empty();
      }
};

template <typename T>
void Stack<T>::push(T const& elem)
{
      elems.push_back(elem);      //將elem的拷貝放入elems末尾
}

template <typename T>
void Stack<T>::pop()
{
      assert(!elems.empty());
      elems.pop_back();      //移除最後一個元素
}

template <typename T>
T const& Stack<T>::top() const
{
      assert(!elems.empty());
      return elems.back();      //返回最後一個元素
}

正如所看到的,該類模板使用C++標準庫的vector<>實現,這樣便無需實現內存管理、拷貝控制和賦值運算,這樣即可以將重心放在類模板的接口上。ide

2.1.1 聲明類模板 Declaration of Class Templates

聲明類模板與聲明函數模板相似:在聲明以前,必須聲明一個或多個類型參數的標識符。再一次,T是一個經常使用的標識符:函數

template <typename T>
class Stack
{
...
};

此處的關鍵字typename也能夠用class代替:spa

template <class T>
class Stack
{
...
};

在類模板中,T能夠像其餘任何類型同樣用於聲明成員和成員函數(member function)。該例子中,T用於聲明成員的類型爲T的向量vector ,用於聲明成員函數 push()使用T類型做爲參數,用於聲明成員函數 top()的返回類型。 code

template <typename T>
class Stack
{
private:
      std::vector<T> elems;      //元素

public:
      void push(T const& elem);      //壓入元素
      void pop();      // 彈出元素
      T const& top() const;      //返回頂上的元素
      bool empty()      //返回棧stack是否爲空
      {
            return elems.empty();
      }
};

該類的類型爲Stack ,其中T爲模板參數。所以,只要在聲明中使用該類的類型,必須使用Stack ,除非模板參數能夠推斷而得。然而,在類模板內,使用沒有模板實參的類名意味着將類模板實參做爲模板參數(However, inside a class template using the class name not followed by template arguments represents the class with its template parameters as its arguments.)(詳見13.2.3節)。 htm

好比,若是必須聲明構造函數和賦值運算符,這一般看起來像這樣:blog

template <typename T>
class Stack
{
      ...
      Stack(Stack const&);      //拷貝構造
      Stack& operator=(Stack const&);      //賦值運算符
};

這與以下形式等價:接口

template <typename T>
class Stack
{
      ...
      Stack(Stack<T> const&);      //拷貝賦值
      Stack<T>& operator=(Stack<T> const&);      //賦值運算符
};

但一般 意味着對特殊模板參數的特殊處理,所以第一種形式更好。 內存

然而,在類結構以外須要指定模板參數:

template <typename T>
bool operator==(Stack<T> const& lhs, Stack<T> const& rhs);

注意到在須要類名而不是類的類型的地方,僅僅使用Stack即可以。這特別是在構造函數和析構函數名字的情形中。

與非模板類不一樣,不能在函數內部或者塊做用域(block scope)內聲明類模板。一般,模板只能定義在全局做用域(global scope)或者命名空間做用域(namespace scope)或者類聲明內(詳見12.1節)。

2.1.2 成員函數實現 Implementation of Member Functions

定義類模板的成員函數必須指定這是一個模板且必須使用類模板的完整類型限制。所以,類型Stack 的成員函數 push()的實現爲

template <typename T>
void Stack<T>::push(T const& elem)
{
      elems.push_back(elem);      //將elem的拷貝放入elems末尾
}

該狀況下,成員向量的push_bask()方法被調用,將元素放入向量vector的末尾。

注意到向量vector的pop_back()將移除最後一個元素但不返回,這行爲的緣由是異常安全(exception safety)。不可能實現一個返回移除元素的徹底異常安全的pop()版本(該問題首先由Tom Cargill在[CargilExceptionSafety]中的第10項條款[SutterExceptional]中討論)。然而,若是忽略該危險,能夠實現返回移除的元素的pop()。爲實現此功能,簡單地使用T來聲明類型爲元素類型的局部變量:

template <typename T>
T Stack<T>::pop()
{
      assert(!elems.empty());
      T elem = elems.back();      //保存最後一個元素
      elems.pop_back();      //移除最後一個元素
      return elem;      //返回保存元素的拷貝
}

因爲當vector中沒有元素時,back()(返回最後一個元素)和pop_back()(移除最後一個元素)都將有未定義的行爲,所以須要檢查棧是否爲空。若是爲空,則斷言(assert),由於在空的棧上調用pop()是錯誤的。在top()上也須要這麼作,它返回頂上的元素但不移除:

template <typename T>
T const& Stack<T>::top() const
{
      assert(elems.empty());
      return elems.back();      //返回最後一個元素
}

固然,對於任何成員函數,也能夠將類模板的成員函數在類的聲明中實現爲inline,好比:

template <typename T>
class Stack
{
      ...
      void push(T const& elem)
      {
            elems.push_back(elem);      //將elem放入末尾
      }
};
相關文章
相關標籤/搜索