C++裏的模板

 1、泛型編程

——即實現一個通用的標準容器庫。所謂通用的標準容器庫,就是要做到:比如List類存放所有肯恩類型的對象這樣的事;泛型編程讓你編寫一個完全一般化並可重複使用的算法,其效率與針對某特定數據類型而設計的算法相同。泛型即是指具有在多種數據類型上皆可操作的意思,與模板有些類似。

——泛型編程的代表作品STL是一種高效、泛型、可交互操作的軟件組件。


2、怎樣編寫一個通用的加法??

     1》使用函數重載,針對每個所需相同行爲的不同類型重新實現它。

     缺點:1》只要有新類型出現,就要重新添加對應函數。

               2》除類型外,所有函數的函數體都相同,代碼的複用率不高。

               3》如果函數只是返回值類型不同,函數重載不能解決問題。

               4》一個方法有問題,所有的方法都有問題,不好維護。

     2》使用公共基類,將通用代碼放在公共基類裏面。

     缺點:1》藉助公共基類來編寫通用代碼,將失去類型檢查的優點。

               2》對於以後實現的很多類,都必須繼承自某個特定的基類,代碼維護更加困難。

     3》使用特殊的預處理程序。

     缺點:1》不是函數,不進行參數類型檢查,安全性不高。

     4》還可以使用泛型編程。


3、泛型編程:

     1》編寫與類型無關的邏輯代碼,是代碼複用的一種手段。模板是泛型編程的基礎。

     2》模板分爲:函數模板、類模板


4、函數模板:

    1》函數模板代表了一個函數家族,在使用時被參數化,根據實參類型產生函數的特定類型。

    2》函數模板的格式:spacer.gif

wKiom1cWMjzzztKSAABK5SwBVXI784.png

     注意:1>typename是用來定義模板參數關鍵字,也可以使用class(建議儘量使用typename)

               2>但是不能使用struct

     3》函數模板也可以定義成inline函數。(但是inline必須放在模板參數表之後,返回值之前,不能放在template之前)


spacer.gif

   4》模板是一個藍圖,它本身不是類或者函數,編譯器用模板產生特定的類或者函數的特定類型版本,產生模板特定類型的過程稱爲函數模板實例化。


5、實參推演:

     從函數實參確定模板形參類型和值的過程叫做模板實參推演。多個類型形參的實參必須完全匹配。


6、類型形參轉換:

     1》一般不會轉換實參來匹配已有的實例化,相反會產生新的實例。

     2》編譯器只會執行兩種轉換:

           1>const轉換:接收const引用或者const指針的函數可以分別用非const對象的引用或者指針來調用

           2>數組或者函數到指針的轉換:如果模板形參不是引用類型,則對數組或者函數類型的實參應該用常規指針轉換。數組實參將當做指向其第一個元素的指針,函數實參當做指向函數類型的指針。


7、模板參數:

    1》函數模板有兩種類型的參數:模板參數和調用參數。

    2》而模板參數又分爲:類型形參和非類型形參

    3》模板形參名字只能在模板形參之後到模板聲明或定義的結尾之間使用,遵循名字屏蔽規則。

    4》模板形參的名字在同一模板形參列表中只能使用一次。

    5》所有模板形參前面必須加上class或者typename關鍵字修飾。

    6》注意在函數模板內部不能指定缺省的模板實參。


8、非模板類型形參:

     非模板類型形參是在模板內部定義的常量,在需要常量表達式的時候,可以使用非模板類型參數。


9、模板形參說明:

     1》模板形參表使用<>括起來。

     2》和函數參數表一樣,跟多個參數時必須用逗號隔開,類型可以相同也可以不同。

     3》模板形參表不能爲空。

     4》模板形參可以是類型形參,也可以是非類型形參。類型形參跟在class和typename之後。

     5》模板類型形參可作爲類型說明符用在模板中的任何地方,與內置類型或自定義類型的使用方法完全相同,可用於指定函數形參類型、返回值、局部變量和強制類型轉換。

     6》模板參數表中,class和typename具有形同的含義,可以互相交換,使用typename更加直觀。但是關鍵字typename是作爲C++標準加入到C++中,就得編譯器可能不支持。


9+、模板函數重載:

      注意:函數和所有的重載版本的聲明都應該位域該函數被調用位置之前。

      說明:

       1》一個非模板函數可以和一個同名的函數模板同時存在,而且該函數模板可以被實例化爲這個非模板函數。

       2》對於非模板函數和同名函數模板,如果其他條件都相同,再調用時會優先調用非模板函數,而不會從該模板產生一個實例化。如果模板可以產生一個具有更好匹配的函數,那麼將選擇模板。

       3》顯示指定一個空的模板實參列表,該語法告訴編譯器只有姆安巴你才能匹配這個調用。而且所有的模板都應該根據實參演繹出來。

       4》模板函數不允許自動類型轉換,但普通函數可以進行自動類型轉換。


10、函數模板的特化:

        模板函數特化形式如下:

        1》關鍵字template後面接一對空的尖括號<>

        2》再接模板名和一對尖括號,尖括號中指定這個特化定義的模板形參

        3》函數形參表

        4》函數體

      注意:在特化之前,這個函數模板必須已經存在,並且兩者形參個數一樣。

template<typename T>
bool IsEqual(T left, T right)
{
                 return left == right;
}
template<>
bool IsEqual<const char*>( const char * pleft, const char * pright) //這裏的<const char*>就相當於代替了T
{
                 return pleft == pright;
}

11、模板參數——適配器:stack(使用模板實現棧——後進先出)

template <typename T>

class SeqList

{

private :

     int _size ;

     int _capacity ;

     T* _data ;

};



// template <class T, template<class> class Container>
template <class T, template<class> class Container = SeqList> // 缺省參數
class Stack
{
public :
     void Push(const T& x );
     void Pop();
     const T& Top();
     bool Empty();
private :
     Container<T > _con;
};
void Test()
{
     Stack<int> s1;
     Stack<int , SeqList> s2;
}
模板的模板參數——實現隊列
template<typename T,template< typename T > class Containter> //再嵌套一個模板類型參數,,這裏的關鍵字一定是class————只有類模板參數才能指定缺省值
class Queue
{
public:
                Queue()
                {}
                 void PushBack(const T& d)
                {
                                _con.PushBack();
                }
                 void PopFront()
                {
                                _con.PopFront();
                }
private:
                 Containter<T > _con;
};

int main()
{
                 Queue<int ,SeqList> q;
                q.PushBack(1);
                q.PushBack(2);
                q.PopFront();
                 return 0;
}

12、非類型的模板參數:

// 靜態順序表
//template<typename T, size_t MAX_SIZE>
template <typename T, size_t MAX_SIZE = 10> //帶缺省模板參數
class SeqList
{
public :
     SeqList();
private :
     T _array [MAX_SIZE];
     int _size ;
};

template <typename T, size_t MAX_SIZE>
SeqList <T, MAX_SIZE>::SeqList()
    : _size(0)
{}

void Test()
{
     SeqList<int> s1;
     SeqList<int , 20> s2;
}


13、模板類:

模板類也是模板,必須以關鍵字template開頭,後接模板形參表。


14、模板類的實例化:

       1》只要有一種不同的類型,編譯器就會實例化出一個對應的類。

       2》 SeqList<int > sl1    SeqList<double > sl2;當定義上述兩種類型的順序表時,編譯器會使用int和double分別代替模板形參,重新編寫SeqList類,最後創建名爲SeqList<int>和SeqList<double>的類。


15、類模板的特化:分兩種——局部特化、全特化

 注意:全特化後定義成員函數,不再需要模板形參   

      1》類型萃取

      2》POD類型萃取


16、模板的分離編譯:

wKioL1cWMySSaIBrAADYeif_S0Q337.png

spacer.gif

——解決方法:

       1》在模板頭文件 xxx.h 裏面顯示實例化->模板類的定義後面添加 template class SeqList<int >; 一般不推薦這種方法,一方面老編譯器可能不支持,另一方面實例化依賴調用者。(不推薦)

       2》將聲明和定義放到一個文件 "xxx.hpp" 裏面,推薦使用這種方法


17、模板總結:

    ——優點:

                1》模板複用了代碼,節省資源,更快的迭代開發,C++的標準模板庫(STL)因此而產生。

                2》增強了代碼的靈活性。

    ——缺點:

                1》模板讓代碼變得凌亂複雜,不易維護,編譯代碼時間變長。

                2》 出現模板編譯錯誤時,錯誤信息非常凌亂,不易定位錯誤。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章