中国大学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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值