程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 函數模板與模板函數,函數模板模板函數

函數模板與模板函數,函數模板模板函數

編輯:C++入門知識

函數模板與模板函數,函數模板模板函數


1.函數指針——指針函數 

函數指針的重點是指針。表示的是一個指針,它指向的是一個函數,例子: 

int   (*pf)(); 

指針函數的重點是函數。表示的是一個函數,它的返回值是指針。例子: 

int*   fun(); 

2.數組指針——指針數組 

數組指針的重點是指針。表示的是一個指針,它指向的是一個數組,例子: 

int   (*pa)[8]; 

指針數組的重點是數組。表示的是一個數組,它包含的元素是指針。例子; 

int*   ap[8]; 

3.類模板——模板類(class   template——template   class) 

類模板的重點是模板。表示的是一個模板,專門用於產生類的模子。例子: 

template   <typename   T> 

class   Vector 



            … 

}; 

使用這個Vector模板就可以產生很多的class(類),Vector <int> 、Vector <char> 、Vector <   Vector <int>   > 、Vector <Shape*> ……。 

模板類的重點是類。表示的是由一個模板生成而來的類。例子: 

上面的Vector <int> 、Vector <char> 、……全是模板類。 

這兩個詞很容易混淆,我看到很多文章都將其用錯,甚至一些英文文章也是這樣。將他們區分開是很重要的,你也就可以理解為什麼在定義模板的頭文件.h時,模板的成員函數實現也必須寫在頭文件.h中,而不能像普通的類(class)那樣,class的聲明(declaration)寫在.h文件中,class的定義(definition)寫在.cpp文件中。

array是一個模板,array<int, 50>是一個模板實例 - 一個類型。從array創建array<int, 50>的過程就是實例化過程。實例化要素體現在main.cpp文件中。如果按照傳統方式,編譯器在array.h文件中看到了模板的聲明,但沒有模板的定義,這樣編譯器就不能創建類型array<int, 50>。但這時並不出錯,因為編譯器認為模板定義在其它文件中,就把問題留給鏈接程序處理。

現在,編譯array.cpp時會發生什麼問題呢?編譯器可以解析模板定義並檢查語法,但不能生成成員函數的代碼。它無法生成代碼,因為要生成代碼,需要知道模板參數,即需要一個類型,而不是模板本身。

這樣,鏈接程序在main.cpp 或 array.cpp中都找不到array<int, 50>的定義,於是報出無定義成員的錯誤。


關於一個缺省模板參數的例子: 

template   <typename   T   =   int> 

class   Array 



            … 

}; 

第一次我定義這個模板並使用它的時候,是這樣用的: 

Array   books;//我認為有缺省模板參數,這就相當於Array <int>   books 

上面的用法是錯誤的,編譯不會通過,原因是Array不是一個類。正確的用法是Array <>   books; 

這裡Array <> 就是一個用於缺省模板參數的類模板所生成的一個具體類。 

4.函數模板——模板函數(function   template——template   function) 

函數模板的重點是模板。表示的是一個模板,專門用來生產函數。例子: 

template   <typename   T> 

void   fun(T   a) 



            … 



在運用的時候,可以顯式(explicitly)生產模板函數,fun <int> 、fun <double> 、fun <Shape*> ……。 

也可以在使用的過程中由編譯器進行模板參數推導,幫你隱式(implicitly)生成。 

fun(6);//隱式生成fun <int> 

fun(8.9);//隱式生成fun <double> 

fun(‘a’);//   隱式生成fun <char> 

Shape*   ps   =   new   Cirlcle; 

fun(ps);//隱式生成fun <Shape*> 

模板函數的重點是函數。表示的是由一個模板生成而來的函數。例子: 

上面顯式(explicitly)或者隱式(implicitly)生成的fun <int> 、fun <Shape*> ……都是模板函數。 

模板本身的使用是很受限制的,一般來說,它們就只是一個產生類和函數的模子。除此之外,運用的領域非常少了,所以不可能有什麼模板指針存在的,即指向模板的指針,這是因為在C++中,模板就是一個代碼的代碼生產工具,在最終的代碼中,根本就沒有模板本身存在,只有模板具現出來的具體類和具體函數的代碼存在。 

提醒:在本文的幾個術語中,語言的重心在後面,前面的詞是作為形容詞使用的。 

 

2 函數模板的異常處理

函數模板中的模板形參可實例化為各種類型,但當實例化模板形參的各模板實參之間不完全一致時,就可能發生錯誤,如:

template<typename T>       
void min(T &x, T &y)
{  return (x<y)?x:y;  }

void func(int i, char j)
{
   min(i, i);
   min(j, j);

   min(i, j);   
   min(j, i);
}

例子中的後兩個調用是錯誤的,出現錯誤的原因是,在調用時,編譯器按最先遇到的實參的類型隱含地生成一個模板函數,並用它對所有模板函數進行一致性檢查,例如對語句

min(i, j);

先遇到的實參i是整型的,編譯器就將模板形參解釋為整型,此後出現的模板實參j不能解釋為整型而產生錯誤,模板函數是沒有隱含的類型轉換功能的。解決此種異常的方法有兩種:

⑴采用強制類型轉換,如將語句min(i, j);改寫為min(i,int( j));

⑵用非模板函數重載函數模板

方法有兩種:

① 借用函數模板的函數體

此時只聲明非模板函數的原型,它的函數體借用函數模板的函數體。如改寫上面的例子如下:

template<typename T>       
void min(T &x, T &y)
{  return (x<y)?x:y;  }

int min(int,int);

void func(int i, char j)
{
   min(i, i);
   min(j, j);

   min(i, j);
   min(j, i);
}

執行該程序就不會出錯了,因為重載函數支持數據間的隱式類型轉換。

② 重新定義函數體

就像一般的重載函數一樣,重新定義一個完整的非模板函數,它所帶的參數可以隨意。

C++中,函數模板與同名的非模板函數重載時,應遵循下列調用原則:

• 尋找一個參數完全匹配的函數,若找到就調用它。若參數完全匹配的函數多於一個,則這個調用是一個錯誤的調用。

• 尋找一個函數模板,若找到就將其實例化生成一個匹配的模板函數並調用它。

• 若上面兩條都失敗,則使用函數重載的方法,通過類型轉換產生參數匹配,若找到就調用它。

•若上面三條都失敗,還沒有找都匹配的函數,則這個調用是一個錯誤的調用。

 

3.函數模板與類模板有什麼區別?

答:函數模板的實例化是由編譯程序在處理函數調用時自動完成的,而類模板的實例化必須由程序員在程序中顯式地指定。

     即函數模板允許隱式調用和顯式調用而類模板只能顯示調用

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved