函数模板(初阶)

       Hello,大家好,我们大家都知道,C++这个编程语言是由C语言继承而来的,因为是继承,所以我们的C++就要做出一些区分,要不然的话,就和C语言没有本质上的区别了,我们现在在社会中使用比较多的是C++而非是C语言,是因为这里我们C++的祖师爷在C语言的基础之上又设计了一个模板相关的内容,这个模板就受到了很多人的欢迎。

1.前情提要

       我们在C语言中经常会使用到一些相同的函数,就比如说Swap函数,我们在前面的C语言编程中就经常会使用到这个Swap函数来交换两个同类型的数据,我们要交换的数据的类型往往不止一种,我们要交换两个int类型的数据,double类型的数据等等,我们要为每一个类型的数据交换都要写一个Swap交换函数,这样就很费时间和空间,这些函数明明达到的效果都是一样的,但是却要写好多的一模一样的函数,很不爽,我们C++的祖师爷考虑到了这种情况,于是,就发明了模板这个东西来改变这种情况。

2.泛型编程

       编写于类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的一种基础。模板又分为函数模板和类模板。

3.函数模板

    3.1函数模板的概念

       函数模板代表了一个函数家族,该函数模板与类型无关,我们在使用时被参数化,根据实参类型从而产生函数的特定类型版本。

    3.2函数模板的格式

template<class T>; 

       class T 就是参数列表的类型,编译器会根据类型来生成对应的函数,为了避免不必要的麻烦,因此这里建议参数列表中有几个形参,这里就写几个:

template<class T1,class T2......>

       比如:在这里写一个Swap交换函数。

#include<iostream>
using namespace std;
template<typename T>
void Swap(T a1, T a2)
{
	T tmp=a1;
	a1 = a2;
	a2 = a1;
}
int main()
{
	int a = 11, b = 22;
	Swap(a, b);//这里我们调用Swap函数的时候,那个Swap模板中的T就被编译器自动识别为int,编译器会自动构造一个int类型的Swap函数。
	cout << a << " " << b << endl;//11 22
	double c = 1.1, d = 2.2;
	Swap(c, d);//当我们传double类型的数据过去的时候,这个Swap函数中的T就会被编译器自动识别为double,编译器会自动构造一个double类型的Swap交换函数。
	cout << c << " " << d << endl;//1.1 2.2
	char e = 'e', f = 'z';
	Swap(e, f);//当我们传char类型的数据过去的时候,这个Swap函数中的T就会被编译器识别为char,编译器会自动构造一个cahr类型的Swap交换函数。
	cout << e << " " << f << endl;//z e
	return 0;
}

注:typename是用来定义模板参数的关键字,我们这里再定义模板参数的时候,其实不仅仅能使用typename这一个关键字,我们还可以使用class这个关键字来代替上述代码中的typename关键字(class/typename这两个关键字的效果都是一样的,不管写谁都可以)。切记:这里不可以使用struct来代替class。

template<class T1,class T2>

    3.3函数模板的原理

       函数模板类似于就是一个蓝图一样,是编译器的使用方式产生特定具体类型函数的摸具。总结下来就是将原本应该有我们做的重复的事情交给了编译器去做。

template<typename T1,typename T2>
void swap(T1& x,T2& y)
{   }

       在编译器的编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演并生成对应类型的函数,以供我们去使用,就比如说,当int类型处理上述的函数时,编译器会通过对实参类型的推演将T1,T2确定为是int类型,然后产生一份专门处理int类型的代码,任何类型均是如此。

    3.4函数模板的实例化

       用函数模板生成对应的函数这个过程成为是模板的实例化。

       (1).隐式实例化:让编译器根据参数来推演模板参数的实际类型。

#include<istream>
using namespace std;
template<class T>//这里我们传过来的参数有几种类型,我们在这里就定义几个class/typename。
T add(T& a1, T& a2)
{
	return a1 + a2;
}
template<class T1,class T2>//这里我们传过来的参数有几种类型,我们在这里就定义几个class/typename。
void Add(T1& b1, T2& b2)
{
	int a = b1 + b2;
}
int main()
{
	int a1 = 1, a2 = 2;
	add(a1,a2);//编译器会自动根据出过去的实参(也就是a1和a2的类型)确定出T为int。
	double b1 = 1.1, b2 = 2.2;
	add(b1, b2);//编译器会自动根据出过去的实参(也就是b1和b2的类型)确定出T为double。
	Add(a1,b2);//编译器会自动根据出过去的实参(也就是a1和b2的类型)确定出T1为int类型,确定出T2为double类型。
	return 0;
}

注意:这里我们传过来的参数有几种类型,我们在这里就定义几个class/typename,如果我们传过去的参数类型有两种的话,但是我们定义的class/typename只有一种的话,那么,这样的话,编译器就无法分清这里定义的这个T是哪一个类型,就会出现编译报错的问题。

       (2).显示实例化:在函数名后面的<  >中指定模板参数的类型。

#include<istream>
using namespace std;
template<class T1,class T2>//这里我们传过来的参数有几种类型,我们在这里就定义几个class/typename。
void Add(T1& b1, T2& b2)
{  }
int main()
{
	int a1 = 1, a2 = 2;
	Add<int, int>(a1, a2);//T1是int类型,T2也是int类型。
	double b1 = 1.1, b2 = 2.2;
	Add<double, double>(b1, b2);//T1是double类型,T2也是double类型。
	Add<int, double>(a1, b2);//T1是int类型,T2是double类型。
	return 0;
}

注意:1>.这个显示实例化的知识我们必须要掌握,这个知识点我们在后面会大量使用。

           2>.如果类型不匹配的话,那么编译器就会尝试着进行类型转换的操作,如果这个类型转换无法成功的话,编译器就会进行报错的操作。

    3.5模板参数的匹配原则

       (1).一个非模板函数可以和一个同名的函数木模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

       (2).对于非模板函数和同名函数模板,如果其他的条件都相同的话,那在调用时会优先调用非模板函数,而不会从该模板中产生一个实例。如果模板可以产生一个具有更好匹配的函数,那么就会选择模板(换句话说,就是有现成的就用现成的,而不会自己创造一个)。

       (3).模板函数不允许自动类型转换,但普遍函数却可以进行自动类型转换。

4.类模板

    4.1类模板的格式

template<typename T1,typename T2>
class date//date是类模板名
{
	//类内成员变量
};

    4.2类模板的实例化

       类模板的实例化与函数模板的实例化不同,类模板实例化需要在类模板名字后面跟<  >,然后将类型放在<  >中即可,类模板的名字其实不是真正的类,而实例化的结果才是真正的类。

#include<iostream>
using namespace std;
template<typename T>
class date//定义了一个类类型的模板
{
public:
	//我们在模板里面实现一个Add函数
	T Add(T& a1,T& a2)
	{   }
	void Swap(T& b1, T& b2);
};
//接下来,我们来写一下Swap函数的定义,在写之前这里还必须要补充一个知识点,就是每一个模板的作用域它仅限于当前的这个类,除了这个类之后就不管了,因此,对于类外的函数来说,我们就必须还得重新再写一个模板。
template<typename T>
void date<T>::Swap(T& b1, T& b2)
{   }
int main()
{
	date<int> d;//类型名/类型:date<int>   
	//(date<int>即是类型名,同时也是类型)
	return 0;
}

注意:类模板都是显示实例化。

       今天我们关于初阶函数模板的知识就先讲到这里了,谢谢大家的支持,你们的支持就是我坚持的巨大动力。

评论 80
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值