泛型编程之函数模板

一.概念

泛型编程:通俗的讲就是模版。用一种通用的模板来写程序。

模板:又分为函数模版和类模版,这篇博客主要说的是函数模版。

函数模版:实际上是建立一个和函数,函数的类型和函数的形参类型不具体指定,用虚拟的类型来代表,这个通用的函数就称为函数模版。

(注意:凡是函数体相同的函数都可以用这个模版来代替,不必定义多个函数,只需要在模版中定义一次即可,再调用函数时系统会自己根据实参的类型类取代实参中的具体类型

,从而实现了不同函数的功能)

二.函数模版的实现

首先看一段代码:功能呢是实现char类型和 int 类型的两个变量的交换

void myswap1(int &a, int &b)
{
	int c = 0;
	c = a;
	a = b;
	b = c;
}
void myswap2(char &a, char &b)
{
	int c = 0;
	c = a;
	a = b;
	b = c;
}
int main()
{
	int a = 10;
	int b = 20;
	char c = 'c';
	char d = 'd';
	myswap1(a, b);
	myswap2(c, d);
	cout << "a=" << a << "  b=" << b << endl;
	cout << "c=" << c << "  d=" << d << endl;
	system("pause");
	return 0;
}


上述代码虽然实现了功能,但是显的很麻烦,假如我在多加几个类型就要在定义同样的函数好几个.所以C++就提供了函数模版机制,让类型参数化,方便我们去编程。

首先看看泛型编程函数模版的语法用法:

接下来用代码继续解释:

template <typename T>
void myswap(T &a, T&b)
{
	T c;
	c = a;
	a = b;
	b = c;
}
int main()
{
    int a = 10;
    int b = 20;
	char c = 'c';
	char d = 'd';
	//myswap<int>(a, b);//函数模版显示类型调用
	//myswap(a, b);//自动类型推倒
	myswap<char>(c, d);
	 myswap(c, d);
	cout << "a=" << a << "  b=" << b << endl;
	cout << "c=" << c << "  d=" << d << endl;
	system("pause");
	return 0;
}


强化应用:对不同类型的数组进行排序

1.int 类型

template <typename T1, typename T2>
void mysort(T1 *arr, T2 sz)
{
	T2 i, j;
	T1 tmp;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j]>arr[j + 1])
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
template <typename T1, typename T2>
void print(T1 *arr,T2 sz)
{
	T2 i;
        cout << "从小到大排序:";
	for (i = 0; i < sz; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}
int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1};
	int sz = sizeof(arr) / sizeof(arr[0]);
	mysort<int, int >(arr, sz);
	print<int, int >(arr, sz);
	system("pause");
	return 0;
}


2.测试char 类型
	char arr[] = {'f','e','d','c','b','a'};
	int sz = sizeof(arr) / sizeof(arr[0]);
	mysort<char, int >(arr, sz);
	print<char, int >(arr, sz);

自己可以根据自己想测试的类型进行测试~

三.函数模版和函数和普通函数的区别

1.函数模版和函数重载

看如下代码:

template <typename T>
void myswap(T &a, T&b)
{
	cout << "我是模版函数" << endl;
}
void myswap(int a, char b)
{
	cout << "我是普通函数" << endl;
}
int main()
{
	int a = 10;
	char b = 'z';
	myswap(a, b);
	myswap(b, a);
	myswap(a, a);
	system("pause");
	return 0;
}

为什么是这样:1.普通函数的调用,可以进行隐式的类型转换

                             2.函数模版的调用,不会进行隐式的转换。

2.数模版也可以像普通函数一样重载:

①C++编译器优先考虑普通函数

②如果函数模版可以产生一个更好的匹配那么选择函数模版

③可以通过空模版实参列表的语法限定编译器只通过模版匹配

看如下代码:

template <typename T>
void myswap(T a, T b)
{
	cout << "我是两个参数的模版函数" << endl;
}
template <typename T>
void myswap(T a, T b,T c)
{
	cout << "我是三个参数的函数模版" << endl;
}
void myswap(int a, int b)
{
	cout << "我是普通函数" << endl;
}
下面测试调用部分:

int main()
{
	int a = 10;
	int b = 20;
	myswap(a, b);//因为函数模版函数和普通函数同时满足,所以系统优先选择普通函数
	myswap<>(a, b);//如果想通过函数模版调用,加上<>(空模版参数列表),就可以调用函数模版函数
	myswap(3.0, 4.0);//这个时候只有函数模板函数可以产生更好的匹配,所以调用函数模版函数
	myswap(3.0, 4.0, 5.0);//函数模版函数重载
	myswap('a', 10);//参数类型不同,而函模版要求参数类型相同,因为普通函数可以进行隐式转换,所以调用普通函数
	system("pause");
	return 0;
}
结果如下,与上图分析完全符合



四.探究函数模版的机制

1.编译器并不是把函数模版处理成能够处理任意类型的函数

2.编译器从函数模版通过具体类型产生不同的函数

3.编译器会对函数模版进行两次编译:在声明的地方对函数模版代码进行编译,在调用的地方对参数替换后的代码进行编译.

第一次编译:在声明的地方对函数进行词法分析,语法分析,句法分析,产生一个简陋的函数模型。

第二次编译:根据你的调用,产生一个具体的函数原型,如果还有不同参数类型函数模版函数的调用,继续产生一个具体的函数原型。

汇编语言如下图:





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值