当先锋百科网

首页 1 2 3 4 5 6 7

目录

函数模板和普通函数的区别

普通函数与模板函数的本质区别

普通函数与模板函数在一起时的调用规则

编译规则

举例说明

模板函数与普通函数在一起时的调用规则

总体代码


函数模板和普通函数的区别

先举个demo:

template <typename T>
void myswap(T &a, T &b)
{
	T c = 0;
	c = a;
	a = b;
	b = c;
	cout << "hello ....我是模板函数 欢迎 calll 我" << endl;
}

这是我们学习函数模板的第一个案例,假设在这个的基础之上,我们再写一个与其同名的函数:

void myswap(int a, char c)
{
	cout << "a:" << a << "c:" << c << endl;
	cout << "我是普通函数 欢迎来访" << endl;
}

 一观察就可以发现,上面两个函数同名,参数类型不一样,很显然它俩是函数重载的关系。

复习一下:重载是发生在同一个作用域里面,重写是发生在父类与子类直接,而且,重写又可以细分成虚函数重写(将产生多态)和重定义(不是虚函数重写)。

那么当调用上面的两个函数的时候,编译器优先调用那个函数呢?所以,作一下探讨:

先尝试着调用一下:

void main()
{
	int	a = 10;
	char	c = 'z';

	myswap(a, c); // 普通函数的调用:  可以进行隐式的类型转换 
	myswap(c, a); //

	myswap(a, a); // 函数模板函数的调用(本质:类型参数化): 将严格的按照类型进行匹配,不会进行自动类型转换

	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

运行后,结果发现,调用第一个函数"myswap(a, c); "如我们所期,进入了普通函数里面了,这是因为我们的两个参数都与普通函数相对应,而且,函数模板的函数要求对应的两个参数都应该是同一个类型的,所以,肯定不会调用到函数模板的函数中去;

调用第二个函数"myswap(c, a); ",发现第二个函数还是调用到普通函数当中去了,因为函数模板的函数要求函数形参与实参的类型必须要相同,但是,"c"与"a"的形参与实参不相同,所以,肯定不会调用到函数模板创建的函数当中,这就说明函数模板所创建的函数执行的时候,会进行严格的类型匹配,但是呢,普通的函数会有一个隐式的类型转换

再看调用第三个函数"myswap(a, a); ",这函数运行是,函数有可能进行隐式的类型转换,也有可能去调用函数模板创建的函数(因为这两个参数的函数类型都一样啊),经过编译器验证,调用的是函数模板所创建的函数,这是因为第三个函数严格匹配函数模板所创建的函数形式。

普通函数与模板函数的本质区别

当调用函数模板所创建的函数(本质:类型参数化)将严格的按照类型进行匹配,不会自动进行类型的转换,但是普通函数调用的时候,可以进行自动的隐式的类型转换

普通函数与模板函数在一起时的调用规则

编译规则

  • 函数模板可以像普通函数一样被重载
  • C++编译器优先考虑普通函数
  • 如果函数模板可以产生一个更好的匹配,那么选择模板
  • 可以通过空模板实参列表的语法限定编译器只通过模板匹配

举例说明

看如下三个函数,一次命名为(为了下面好区分,简单的做个命名)A,B,C函数:

int Max(int a, int b)
{
	cout<<"int Max(int a, int b)"<<endl;
	return a > b ? a : b;
}

template<typename T>
T Max(T a, T b)
{
	cout<<"T Max(T a, T b)"<<endl;
	return a > b ? a : b;
}
template<typename T>
T Max(T a, T b, T c)
{
	cout<<"T Max(T a, T b, T c)"<<endl;
	return Max(Max(a, b), c);
}

主调函数进行调用:

void main()
{
	int a = 1;
	int b = 2;

	cout<<Max(a, b)<<endl; //当函数模板和普通函数都符合调用时,优先选择普通函数
	cout<<Max<>(a, b)<<endl; //若显示使用函数模板,则使用<> 类型列表

	cout<<Max(3.0, 4.0)<<endl; //如果 函数模板产生更好的匹配 使用函数模板

	cout<<Max(5.0, 6.0, 7.0)<<endl; //重载

	cout<<Max('a', 100)<<endl;  //调用普通函数 可以隐式类型转换 
	system("pause");
	return ;
}

下面来分析,看第一个函数"cout<<Max(a, b)<<endl;",一观察就可以发现,这个函数的形参为两个,而且数据类型一样,所以,肯定是在A和B这两个函数之间考虑了,这个时候,普通函数要比模板函数更优先使用,这是因为普通函数的调用场景已经有了,如果选择模板函数,还需要先生成对应的类型,所以,会优先执行A函数,即普通函数。

再看第二个函数"cout<<Max<>(a, b)<<endl;",这样就是强制告诉编译器,要使用B(模板)函数。

再看第三个函数"cout<<Max(3.0, 4.0)<<endl;",这个输入的值是浮点数类型,跟普通函数的默认类型不匹配,如果隐式的将浮点类型转为整型会造成数据的失真,这个时候编译器会优先使用A(模板)函数。

再看第四个函数"cout<<Max(5.0, 6.0, 7.0)<<endl;"这个有三个参数,A(普通)函数,无论如何无法满足需求,只有C函数能满足需求,毫无疑问调用C(三个参数的)函数。

最后一个函数"cout<<Max('a', 100)<<endl; ",第一个参数类型是"char",第二个参数类型"int"类型的,这个时候,模板函数因为会严格执行类型匹配无法满足我们的需求,故会调用A(普通)函数来执行。

模板函数与普通函数在一起时的调用规则

  • 当函数模板和普通函数都符合调用时,优先选择普通函数
  • 若显示使用函数模板,则使用<> 类型列表
  • 如果函数模板产生更好的匹配,则使用函数模板
  • 调用普通函数,可以隐式类型转换,而模板函数必须严格执行类型匹配,不能不一样。 

总体代码

dm03_函数模板遇上函数重载.cpp


#include <iostream>
using namespace std;



//让 类型参数化 ===, 方便程序员进行编码
// 泛型编程 
//template 告诉C++编译器 我要开始泛型编程了 .看到T, 不要随便报错
template <typename T>
void myswap(T &a, T &b)
{
	T c = 0;
	c = a;
	a = b;
	b = c;
	cout << "hello ....我是模板函数 欢迎 calll 我" << endl;
}

void myswap(int a, char c)
{
	cout << "a:" << a << "c:" << c << endl;
	cout << "我是普通函数 欢迎来访" << endl;
}


void main()
{
	int		a = 10;
	char	c = 'z';

	myswap(a, c); // 普通函数的调用:  可以进行隐式的类型转换 
	myswap(c, a); //

	myswap(a, a); // 函数模板函数的调用(本质:类型参数化): 将严格的按照类型进行匹配,不会进行自动类型转换

	
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

dm04_函数模板和普通函数在一起调用规则研究.cpp


/*
函数模板不允许自动类型转化
普通函数能够进行自动类型转换
*/

/*
	1 函数模板可以像普通函数一样被重载
	2 C++编译器优先考虑普通函数
	3 如果函数模板可以产生一个更好的匹配,那么选择模板
	4 可以通过空模板实参列表的语法限定编译器只通过模板匹配
*/


#include "iostream"
using namespace std;


int Max(int a, int b)
{
	cout<<"int Max(int a, int b)"<<endl;
	return a > b ? a : b;
}

template<typename T>
T Max(T a, T b)
{
	cout<<"T Max(T a, T b)"<<endl;
	return a > b ? a : b;
}

template<typename T>
T Max(T a, T b, T c)
{
	cout<<"T Max(T a, T b, T c)"<<endl;
	return Max(Max(a, b), c);
}


void main()
{
	int a = 1;
	int b = 2;

	cout<<Max(a, b)<<endl; //当函数模板和普通函数都符合调用时,优先选择普通函数
	cout<<Max<>(a, b)<<endl; //若显示使用函数模板,则使用<> 类型列表

	cout<<Max(3.0, 4.0)<<endl; //如果 函数模板产生更好的匹配 使用函数模板

	cout<<Max(5.0, 6.0, 7.0)<<endl; //重载

	cout<<Max('a', 100)<<endl;  //调用普通函数 可以隐式类型转换 
	system("pause");
	return ;
}