中國大學MOOC程序設計與算法(三):C++ 面向對象程序設計 第七週 輸入輸出和模板 筆記 之 函數模板

第七週 輸入輸出和模板
1.輸入輸出流相關的類
2.用流操縱算子控制輸出格式
3.文件讀寫(一)
4.文件讀寫(二)
5.函數模板
6.類模板
7.類模板與派生、友元和靜態成員變量

5.函數模板

C++爲了提高程序的可重用性,一方面有繼承機制,另一方面採用泛型程序設計,也就是模板(函數模板和類模板)。

函數模板:如果要寫多個很相似的函數,可以先寫一個模板,然後用這個模板實例化。

例子:
交換兩個整型變量的值的Swap函數:

void Swap(int & x,int & y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

交換兩個double型變量的值的Swap函數:

void Swap(double & x,double & y)
{
	double tmp = x;
	x = y;
	y = tmp;
}

能否只寫一個Swap,就能交換各種類型的變量?

用函數模板解決:

template <class 類型參數1class 類型參數2,……>
返回值類型 模板名 (形參表)
{
	函數體
};
template <class T>
void Swap(T & x,T & y)
{
	T tmp = x;
	x = y;
	y = tmp;
}
int main()
{
	int n = 1,m = 2;
	Swap(n,m); //編譯器自動生成 void Swap(int & ,int & )函數
	double f = 1.2,g = 2.3;
	Swap(f,g); //編譯器自動生成 void Swap(double & ,double & )函數
	return 0;
}

函數模板中可以有不止一個類型參數。

template <class T1, class T2>
T2 print(T1 arg1, T2 arg2)
{
	cout<< arg1 << " "<< arg2<<endl;
	return arg2;
}

例子:求數組最大元素的MaxElement函數模板

template <class T>
T MaxElement(T a[], int size) //size是數組元素個數
{
	T tmpMax = a[0];
	for( int i = 1;i < size;++i)
		if( tmpMax < a[i] )
			tmpMax = a[i];
	return tmpMax;
}

編譯器通過模板生成函數的過程,叫做模板的實例化。當編譯器遇到調用模板的語句時,會根據實參的類型,進行實例化。
例子:也可以不通過參數實例化函數模板

#include <iostream>
using namespace std;
template <class T>
T Inc(T n)
{
	return 1 + n;
}
int main()
{
	cout << Inc<double>(4)/2; //輸出 2.5
	return 0;
}

函數模板的重載

函數模板可以重載,只要它們的形參表或類型參數表不同即可。

template<class T1, class T2>
void print(T1 arg1, T2 arg2) {
		cout<< arg1 << " "<< arg2<<endl;
}
template<class T>
void print(T arg1, T arg2) {
	cout<< arg1 << " "<< arg2<<endl;
}
template<class T,class T2>
void print(T arg1, T arg2) {
	cout<< arg1 << " "<< arg2<<endl;
}

函數模板和函數的次序

在有多個函數和函數模板名字相同的情況下,編譯器如下處理一條函數調用語句
(1) 先找參數完全匹配的普通函數(非由模板實例化而得的函數)。
(2) 再找參數完全匹配的模板函數。
(3) 再找實參數經過自動類型轉換後能夠匹配的普通函數。
(4) 上面的都找不到,則報錯。

template <class T>
T Max( T a, T b) {
	cout << "TemplateMax" <<endl; 
	return 0;
}
template <class T,class T2>
T Max( T a, T2 b) {
	cout << "TemplateMax2" <<endl; 
	return 0;
}
double Max(double a, double b){
	cout << "MyMax" << endl;
	return 0;
}
int main() {
	int i=4, j=5;
	Max( 1.2,3.4); // 輸出MyMax
	Max(i, j); //輸出TemplateMax
	Max( 1.2, 3); //輸出TemplateMax2
	return 0;
}

匹配模板函數時,不進行類型自動轉換

template<class T>
T myFunction( T arg1, T arg2)
{ 
	cout<<arg1<<" "<<arg2<<"\n"; 
	return arg1;
}
……
myFunction( 5, 7); //ok:replace T with int
myFunction( 5.8, 8.4); //ok:replace T with double
myFunction( 5, 8.4); //error ,no matching function for call to 'myFunction(int, double)'

函數模板示例:Map

#include <iostream>
using namespace std;
template<class T,class Pred>
//將區間[s,e)做op變換,然後拷貝到以x開始的區間
void Map(T s, T e, T x, Pred op)//op是個處理函數
{
	for(; s != e; ++s,++x) {
		*x = op(*s);
	}
}
int Cube(int x) { 
	return x * x * x; 
}
double Square(double x) { 
	return x * x; 
}
int a[5] = {1,2,3,4,5}, b[5];
double d[5] = { 1.1,2.1,3.1,4.1,5.1} , c[5];
int main() {
	Map(a,a+5,b,Square);
	for(int i = 0;i < 5; ++i) 
		cout << b[i] << ",";
	cout << endl;
	
	Map(a,a+5,b,Cube);
		for(int i = 0;i < 5; ++i) cout << b[i] << ",";
	cout << endl;
	
	Map(d,d+5,c,Square);
		for(int i = 0;i < 5; ++i) cout << c[i] << ",";
	cout << endl;
	return 0; 
}
輸出:
1,4,9,16,25,
1,8,27,64,125,
1.21,4.41,9.61,16.81,26.01,

函數中具體是這樣實現的:

template<class T,class Pred>
void Map(T s, T e, T x, Pred op) {
	for(; s != e; ++s,++x) {
		*x = op(*s);
	}
}
int a[5] = {1,2,3,4,5}, b[5];
Map(a,a+5,b,Square); //實例化出以下函數:
void Map(int * s, int * e, int * x, double ( *op)(double)) {
	for(; s != e; ++s,++x) {
		*x = op(*s);
	}
}

Square是普通函數的名字,可以作爲函數模板的參數,那麼實例化時,op就別替換成一個指向函數Squared的函數指針,Pred就是函數Square的返回值類型double。

發佈了53 篇原創文章 · 獲贊 4 · 訪問量 1988
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章