1. 程式人生 > >C++ 重點知識梳理(五) --------- 泛指型別

C++ 重點知識梳理(五) --------- 泛指型別

六、泛型程式設計

6.1 使用模板的優點和缺點?

優點:

  1. 在一些場景可以避免重複程式碼
  2. 有些問題難以使用OO技巧(如繼承和多型)來實現,而使用模版會很方便
  3. template classes更加的型別安全,因其引數型別在編譯時都是已知的。

缺點:

  1. 一些編譯器對template支援不好。
  2. 編譯器給出的有些出錯資訊比較晦澀。
  3. 為每種型別都生成額外的程式碼,可能導致生成的exe膨脹。
  4. 使用templates寫的程式碼難以除錯
  5. templates在標頭檔案中,這樣一旦有所變更需要重編譯所有相關工程

6.2 模板函式和函式的對比?

  1. 模板函式由函式模板例項化而來,編譯器推斷模板實參,然後例項化出對應的函式定義。模板函式是函式模板的例項。
  2. 普通函式需要程式設計師手動過載才能實現對於不同型別引數的支援。
  3. 函式模板只能用於函式的引數個數相同而型別不同的情況,如果引數個數不同,則不能使用函式模板,只能使用過載。
  4. 函式模板必須要求所有實參的型別T都相同,無法進行隱式型別轉換。
  5. 進行函式呼叫時,編譯器優先選擇匹配的非模板函式,如果找不到再試著進行函式模板的例項化,如果還不行,則這個呼叫違法。這樣做可以減少函式模板例項化次數,提高效率。

6.3 模板的全特化和偏特化?

什麼是特化?

所謂特化,就是將泛型的東東搞得具體化一些,從字面上來解釋,就是為已有的模板引數進行一些使其特殊化的指定,使得以前不受任何約束的模板引數,或受到特定的修飾(例如const或者搖身一變成為了指標之類的東東,甚至是經過別的模板類包裝之後的模板型別)或完全被指定了下來。

模板有兩種特化,全特化和偏特化(區域性特化) 模板函式只能全特化,沒有偏特化(以後可能有)。 模板類是可以全特化和偏特化的。 全特化,就是模板中模板引數全被指定為確定的型別。 全特化也就是定義了一個全新的型別,全特化的類中的函式可以與模板類不一樣。 偏特化,就是模板中的模板引數沒有被全部確定,需要編譯器在編譯時進行確定。 在型別上加上const、&、*( cosnt int、int&、int*、等等)並沒有產生新的型別。只是型別被修飾了。模板在編譯時,可以得到這些修飾資訊。

模板為什麼要特化,因為編譯器認為,對於特定的型別,如果你能對某一功能更好的實現,那麼就該聽你的。

模板分為類模板與函式模板,特化分為全特化與偏特化。全特化就是限定死模板實現的具體型別,偏特化就是如果這個模板有多個型別,那麼只限定其中的一部分。

先看類模板:

template<typename T1, typename T2>  
class Test  
{  
public:  
    Test(T1 i,T2 j):a(i),b(j){cout<<"模板類"<<endl;}  
private:  
    T1 a;  
    T2 b;  
};  
  
template<>  
class Test<int , char>  
{  
public:  
    Test(int i, char j):a(i),b(j){cout<<"全特化"<<endl;}  
private:  
    int a;  
    char b;  
};  
  
template <typename T2>  
class Test<char, T2>  
{  
public:  
    Test(char i, T2 j):a(i),b(j){cout<<"偏特化"<<endl;}  
private:  
    char a;  
    T2 b;  
}; 

 那麼下面3句依次呼叫類模板、全特化與偏特化:

Test<double , double> t1(0.1,0.2);  
Test<int , char> t2(1,'A');  
Test<char, bool> t3('A',true);

 而對於函式模板,卻只有全特化,不能偏特化: 

//模板函式  
template<typename T1, typename T2>  
void fun(T1 a , T2 b)  
{  
    cout<<"模板函式"<<endl;  
}  
  
//全特化  
template<>  
void fun<int ,char >(int a, char b)  
{  
    cout<<"全特化"<<endl;  
}  
  
//函式不存在偏特化:下面的程式碼是錯誤的  
/* 
template<typename T2> 
void fun<char,T2>(char a, T2 b) 
{ 
    cout<<"偏特化"<<endl; 
} 
*/ 

注意:

  • 至於為什麼函式不能偏特化,似乎不是因為語言實現不了,而是因為偏特化的功能可以通過函式的過載完成。
  • 函式模版的全特化不參與函式過載, 並且優先順序低於函式基礎模版參與匹配,也就是說,匹配的順序是:

1. 非模板函式

2. 某個沒有進行全特化的template function

3. 如果這個沒有進行全特化的template function有全特化版本,並且型別也比較匹配,則選擇這個全特化版本