天天看點

C++ 模闆類

在C++中,模闆類最主要是解決這樣的一個問題:多個類的功能相同,隻是由于資料類型不同而不得不重複定義幾個相似的類,導緻無用的工作量增大和代碼量增多。

模闆定義:模闆就是實作代碼重用機制的一種工具,它可以實作類型參數化,即把類型定義為參數,進而實作了真正的代碼可重用性。模版可以分為兩類,一個是函數模版,另外一個是類模版。

具體執行個體:實作對兩個整數比較、兩個浮點數比較。則我們要重複定義下面兩個類

class Compare_int class Compare_folat

{ {

public : public :

Compare(int iA,int iB) Compare(float fA a,float fB)

{ {

m_iA = a; m_fA = fA ;

m_iB = b; m_fB = fB;

} }

int max(){return (m_iA > m_iB ) ? m_iA : m_iB ;} int max(){return (m_fA > m_fB ) ? m_fA : m_fB ;}

int min(){return (m_iA < m_iB ) ? m_iA :m_iB ;} int min(){return (m_fA < m_fB ) ? m_fA :m_fB ;}

private: private:

int m_ix; int m_fA ;

int m_iy; int m_fB ;

} }

從上面兩個類看出隻有資料類型不同,其他的代碼基本上是一樣的。

有了模闆之後,就可以解決上面重複定義幾個相同功能,但是資料類型不同的類的問題。

可以聲明一個通用的類模闆,它可以有一個或多個虛拟的類型參數,如對以上兩個類可以綜合寫出以下的類模闆:

template <class或typename numtype> //聲明一個模闆,虛拟類型名為numtype。

class Compare //類模闆名為Compare

{

   public :

    Compare(numtype a,numtype b)

    {m_x = a; m_y = b;}

    numtype max( )

    {return (m_x > m_y) ? m_x : m_y;}

    numtype min( )

    {return (m_x < m_y) ? m_x : m_y;}

   private :

    numtype m_x, m_y;

};

将此類模闆和前面第一個Compare_int類作一比較,可以發現有兩處不同:

  1. 聲明類模闆時要增加一行

       template <class 類型參數名>

  2. 原有的類型名int換成虛拟類型參數名numtype。

    在建立類對象時,如果将實際類型指定為int型,編譯系統就會用int取代所有的numtype,如果指定為float型,就用float取代所有的numtype。這樣就能實作“一類多用”。

由于類模闆包含類型參數,是以又稱為參數化的類。如果說類是對象的抽象,對象是類的執行個體,則類模闆是類的抽象,類是類模闆的執行個體。

由于類模闆可以建立各種資料類型的類。在聲明了一個類模闆後,如何通過它建立執行個體。

先回顧一下用具體類來定義對象的方法:

   Compare_int cmp1(4,7); // Compare_int是已聲明的類

用類模闆定義對象的方法與此相似,但是不能直接寫成

   Compare cmp(4,7); // Compare是類模闆名

   Compare是類模闆名,而不是一個具體的類,類模闆體中的類型numtype并不是一個實際的類型,隻是一個虛拟的類型,無法用它去定義對象。

必須用實際類型名去取代虛拟的類型,具體的做法是:

   Compare <int> cmp(4,7);

即在類模闆名之後在尖括号内指定實際的類型名,在進行編譯時,編譯系統就用int取代類模闆中的類型參數numtype,這樣就把類模闆具體化了,或者說執行個體化了。這時Compare<int>就相當于前面介紹的Compare_int類。

還有一個問題要說明: 上面列出的類模闆中的成員函數是在類模闆内定義的。如果改為在類模闆外定義,不能用一般定義類成員函數的形式:

   numtype Compare::max( ) {…} //不能這樣定義類模闆中的成員函數

而應當寫成類模闆的形式:

   template <class numtype>

   numtype Compare<numtype>::max( )

   {{return (x>y)?x:y;}

歸納以上的介紹,可以這樣聲明和使用類模闆:

  1. 先寫出一個實際的類。由于其語義明确,含義清楚,一般不會出錯。
  2. 将此類中準備改變的類型名(如int要改變為float或char)改用一個自己指定的虛拟類型名(如上例中的numtype)。
  3. 在類聲明前面加入一行,格式為

    template <class 虛拟類型參數>,如

    template <class numtype> //注意本行末尾無分号

    class Compare

    {…}; //類體

  4. 用類模闆定義對象時用以下形式:

       類模闆名<實際類型名> 對象名;

       類模闆名<實際類型名> 對象名(實參表列);

       Compare<int> cmp;

       Compare<int> cmp(3,7);

  5. 如果在類模闆外定義成員函數,應寫成類模闆形式:

       template <class 虛拟類型參數>

       函數類型 類模闆名<虛拟類型參數>::成員函數名(函數形參表列) {…}

關于類模闆的幾點說明:

  1. 類模闆的類型參數可以有一個或多個,每個類型前面都必須加class,如

    template <class T1,class T2>

    class someclass

    {…};

    在定義對象時分别代入實際的類型名,如

       someclass<int,double> obj;

  2. 和使用類一樣,使用類模闆時要注意其作用域,隻能在其有效作用域内用它定義對象。
  3. 模闆可以有層次,一個類模闆可以作為基類,派生出派生模闆類。
  4. 模闆類繼承後無法直接調用基類成員,需要使用this->修飾符來通路基類成員

在有些編譯器中類模闆不能分開檔案寫,隻能把定義和具體實作放在同一個檔案中。(因為模闆類在編譯時就相當于宏定義,分兩個檔案是找不到的)

附加:如果模闆函數和函數重載同時使用時,則優先考慮函數重載,再考慮模闆函數,最後考慮類型轉換。

繼續閱讀