1. 程式人生 > 實用技巧 >C++面向物件入門(三十六)模板概念和初步認識函式模板

C++面向物件入門(三十六)模板概念和初步認識函式模板

強型別語言的特點:
1 程式可靠性較高:在編譯執行前必須經過嚴格的型別檢查, 達到在執行前就檢查出型別不相容的錯誤.
2 靈活性較低: 對於默寫處理邏輯完全一樣, 但是資料型別不同的變數的操作必須按照型別分別定義. 解決強型別的嚴格性和靈活性的衝突的途徑:
1 使用巨集函式: 方便, 但是可能不帶來其他安全問題, C++不提倡
2 為每個資料型別過載相同的函式, 麻煩
3 放鬆型別檢查, 在編譯時忽略, 推遲到執行期間作型別匹配檢查, 可能在程式執行期間出現型別不相容的情況
4 將資料型別作為引數(類屬機制Genericity) C++通過模板機制實現類屬機制 模板機制: 一種引數化多型性的工具, 為邏輯功能相同而型別不同的程式提供程式碼共享機制 C++中的模板機制, 模板並非實實在在的函式或類, 僅僅是函式或類的描述, 模板運算物件的型別不是實際的資料型別,
而是一種引數化的型別(類屬型別), 根據使用類似型別的構件, 又分為:
1 類模板:對一批僅有資料型別不同類的抽象, 只需為這一批類組成的整個類家族建立一個類模板, 然後給出一套程式程式碼, 就
可以用來生成多種具體類, 即模板類. 由於類模板需要一種或多種型別引數, 因此又被稱為引數化類
優點:提高程式設計效率, 提高程式碼可重用性 類和類模板: 類是對一族具有公共性質的物件的抽象, 而類模板則是對一組具有公共性質的類的抽象, 類模板是更高層次的抽象化 如何定義類模板?
template<模板引數表>
class <類模板名>
{
<類成員宣告>
} 使用類模板的注意事項:
1 模板引數表包含一個多個用逗號分開的型別, 引數項可以包含基本資料型別, 也可以包含類型別, 如果是類型別, 必須加字首class
或typename
2 類模板的成員函式和過載運算子必須為模板函式, 可以在類內定義, 定義方式和定義成員函式一致, 也可以放在類模板外部, 此時
定義方式如下
template<模板引數名>
<返回值型別> <類模板名>< <型別名錶> >::<成員函式名>(<引數表>)
{
<函式體>
}
3 與函式模板不同的是, 函式模板的例項化是由編譯系統在處理函式呼叫時自動完成, 而類模板的例項化必須在程式中顯式地指定
在類模板例項化為模板類時(使用類模板經例項化而成的具體類), 類模板中的成員函式自動例項化為模板函式 如何定義模板類物件
<類模板名>< <型別實參表> > <物件名>(<實參表>) 對於上述定義方式欄位的解釋:
類名名錶: 類模板定義中的模板引數表中的引數名 如何例項化類模板?
語法:
<類模板名> < <型別實參表> > 2 函式模板: 可以一次定義出具有共性(除型別引數外, 其餘全部相同)的一組函式, 同時也可以處理多種不同型別資料的函式
優點:增強了函式設計的通用性 如何定義函式模板: 先實現函式模板, 然後例項化構造出相應的模板函式進行呼叫執行 定義函式模板的語法:
template<模板引數表>
<返回值型別> <函式名>(<引數表>)
{
<函式體>
} 模板引數表的定義語法;
typename(class) 模板引數名,... 使用函式模板的注意事項:
1 模板引數可以在函式的任何地方使用
2 函式的引數表可以使用模板引數, 也可以使用一般型別引數(基本型別, 使用者自定義型別), 但引數表至少又一個形參的
型別必須使用模板引數表的模板引數,
3 模板引數表中的每一個模板引數都必須在引數表中得到使用
4 函式模板的宣告和定義必須是全域性作用域, 模板不能被宣告為類的成員函式
5 編譯器不會為沒有用到的任何型別生成相應的模板函式
6 一個型別無論使用多少次函式模板, 都只為該型別生成一個模板函式 函式模板的程式碼示例:
#include <iostream>
using namespace std;

/*
強型別語言的特點:
1 程式可靠性較高:在編譯執行前必須經過嚴格的型別檢查, 達到在執行前就檢查出型別不相容的錯誤.
2 靈活性較低: 對於默寫處理邏輯完全一樣, 但是資料型別不同的變數的操作必須按照型別分別定義.
解決強型別的嚴格性和靈活性的衝突的途徑:
1 使用巨集函式: 方便, 但是可能不帶來其他安全問題, C++不提倡
2 為每個資料型別過載相同的函式, 麻煩
3 放鬆型別檢查, 在編譯時忽略, 推遲到執行期間作型別匹配檢查, 可能在程式執行期間出現型別不相容的情況
4 將資料型別作為引數(類屬機制Genericity)
C++通過模板機制實現類屬機制
模板機制: 一種引數化多型性的工具, 為邏輯功能相同而型別不同的程式提供程式碼共享機制
C++中的模板機制, 模板並非實實在在的函式或類, 僅僅是函式或類的描述, 模板運算物件的型別不是實際的資料型別, 
而是一種引數化的型別(類屬型別), 根據使用類似型別的構件, 又分為:
1 類模板:對一批僅有資料型別不同類的抽象, 只需為這一批類組成的整個類家族建立一個類模板, 然後給出一套程式程式碼, 就
可以用來生成多種具體類, 即模板類. 由於類模板需要一種或多種型別引數, 因此又被稱為引數化類
優點:提高程式設計效率, 提高程式碼可重用性
類和類模板: 類是對一族具有公共性質的物件的抽象, 而類模板則是對一組具有公共性質的類的抽象, 類模板是更高層次的抽象化
如何定義類模板?
template<模板引數表>
class <類模板名>
{
 <類成員宣告>
}
使用類模板的注意事項:
1 模板引數表包含一個多個用逗號分開的型別, 引數項可以包含基本資料型別, 也可以包含類型別, 如果是類型別, 必須加字首class
或typename
2 類模板的成員函式和過載運算子必須為模板函式, 可以在類內定義, 定義方式和定義成員函式一致, 也可以放在類模板外部, 此時
定義方式如下
template<模板引數名>
<返回值型別> <類模板名>< <型別名錶> >::<成員函式名>(<引數表>)
{
 <函式體>
}
3 與函式模板不同的是, 函式模板的例項化是由編譯系統在處理函式呼叫時自動完成, 而類模板的例項化必須在程式中顯式地指定
在類模板例項化為模板類時(使用類模板經例項化而成的具體類), 類模板中的成員函式自動例項化為模板函式
如何定義模板類物件
<類模板名>< <型別實參表> > <物件名>(<實參表>)
對於上述定義方式欄位的解釋:
類名名錶: 類模板定義中的模板引數表中的引數名
如何例項化類模板?
語法:
<類模板名> < <型別實參表> >
2 函式模板: 可以一次定義出具有共性(除型別引數外, 其餘全部相同)的一組函式, 同時也可以處理多種不同型別資料的函式
優點:增強了函式設計的通用性
如何定義函式模板: 先實現函式模板, 然後例項化構造出相應的模板函式進行呼叫執行
定義函式模板的語法:
template<模板引數表>
<返回值型別> <函式名>(<引數表>)
{
 <函式體>
}
模板引數表的定義語法;
typename(class) 模板引數名,...
使用函式模板的注意事項:
1 模板引數可以在函式的任何地方使用
2 函式的引數表可以使用模板引數, 也可以使用一般型別引數(基本型別, 使用者自定義型別), 但引數表至少又一個形參的
型別必須使用模板引數表的模板引數,
3 模板引數表中的每一個模板引數都必須在引數表中得到使用
4 函式模板的宣告和定義必須是全域性作用域, 模板不能被宣告為類的成員函式
5 編譯器不會為沒有用到的任何型別生成相應的模板函式
6 一個型別無論使用多少次函式模板, 都只為該型別生成一個模板函式          
*/
//定義函式模板
template<typename T>
T min(T a, T b)
{
 return a < b ? a : b;
}
//嘗試在函式模板引數表中不使用模板引數, 僅在返回值型別和函式內使用
template<typename E>
E func1(int i, double d)
{
 cout << i << " " << d << endl;
 E e;
 return e;
}
//沒有報錯
//但在使用函式模板時會報錯
//嘗試在函式模板引數表中只使用部分模板引數
template<typename E, typename V>
E func2(E e)
{
 cout << e << endl;
}
//沒有報錯
//但在使用函式模板時會報錯
class A53
{
private:
 int x;
 int y;
public:
 A53();
 A53(int, int);
 bool operator<(const A53 &a);
 friend ostream &operator<<(ostream &cout, const A53& a);
};
int main()
{
 double d1, d2;
 d1 = 3.7;
 d2 = 5.3;
 cout << d1 << " and " << d2 << " min is " << min(d1, d2) << endl;
 int i1, i2;
 i1 = 12;
 i2 = 34;
 cout << i1 << " and " << i2 << " min is " << min(i1, i2) << endl;
 char c1, c2;
 c1 = 'a';
 c2 = 'A';
 cout << c1 << " and " << c2 << " min is " << min(c1, c2) << endl;
 A53 a1(2, 1);
 A53 a2(1, 3);
 A53 a3(2, 2);
 cout << a1 << " and " << a2 << " min is " << min(a1, a2) << "}" << endl;
 cout << a1 << " and " << a3 << " min is " << min(a1, a3) << "}" << endl;
 cout << a2 << " and " << a3 << " min is " << min(a2, a3) << "}" << endl;
 A53 a4;
 //A53 a = func2(a4);
 //沒有與引數型別匹配的函式模板'func2'例項
 // 引數型別為(A53)
 //func1(1, 2.5);
 //沒有與引數型別匹配的函式模板'func2'例項
 // 引數型別為(int, double)
 system("pause");
}
A53::A53()
{
 cout << "A53" << endl;
}
A53::A53(int x, int y):x(x),y(y) {}
bool A53::operator<(const A53 & a)
{
 if (x == a.x)
 {
  return y < a.y;
 }
 return x < a.x;
}
ostream & operator<<(ostream & cout, const A53 & a)
{
 cout << "A53{x:" << a.x << ", y:" << a.y;
 return cout;
}