基本的模板语法:
到目前为止,我们已经介绍了两种C++程序设计范型,即:
- 按照面向过程式范型把程序划分成不同的函教
- 按照面向对象式范型把代码和数据组织成各种名样的类并建立类之间的继承关系。
在这一讲里,将给大家介绍另一种范型:泛型编程!
范型编程技术支持程序员创建函数和类的蓝图(即模板,template),而不是具体的函数和类。这些模板可以没有任何类型:它们可以处理的数据并不仅限于某种特定的数据类型。
当程序需要用到这些函数中的某一个时,编译器将根据模板即时生成一个能够对特定数据类型进行处理的泛型编程技术可以让程序员用一个解决方案解决多个问题。 接下来的这几讲里,我们先来学习如何编写和使用色己的泛型代码,然后再跟大家介绍标准模板库(Standard Template Library,STL)。在泛型编程技术里,我么仍然需要编写自己的函数和类,但不必限定它们所使用的数据类型。只需要使用一个占位符(通常用字母T来表示),然后用这个占位符来编写函数。
当程序需要这段代码时,你提供数据类型,编译器将根据你的模板即时生成实用的代码。 简单的说,编译器把模板里的每一个T替换为所提供的数据类型。 是不是有点像那个啥?那个#Define。。。。我们回来说说STL库,STL库是泛型编程技术的经典之作,它包含了许多非常有用的数据类型和算法。
有着这玩意,我们以后装逼那成本敢情就低很多了,有木有!! 好了,咱赶紧落实起来吧,好不容易哄得大家激情万丈,可不能浪费!
以下代码定义了一个名为foo()的函数模板:
templatevoid foo(T param){ //do something}
这里有几件事值得注意:
第一行代码里,在尖括号里有一个class T用来告诉编译器:字母T将在接下来的函数里代表一种不确定的数据类型。关键字class并不意味着这个是类哦,这只是一种约定俗成的写法。
在告诉计等机T是一种类型之后,就可以像对待一种普通数据类型那样使用它了。
函数模板:
举个栗子:交换两个变量的值是一种几乎所有的程序都需要用到的基本操作。因为这种交换如此常见,所以把它编写为一个虽数是个好主意。
void swap(int &a, int &b){ int tmp = a; a = b; b = temp;}
简单分析下:
如果我们想用这个函数来交换两个double类型的变量的值,我们应该怎么办? 没错,我们可以再增加一个swap(double&a,double&b)函数,因为C++支持函数重载。一我们发觉,我们不得不为要交换的每一种数据类型反复编写同样的代码。 这正是函数模板大显身手的地方,你用不着为每一种数据类型分别编写一个函数,只要告诉编译器你已经为此准备好了一个模板就行了!这样子等你再使用swap()函教时,编译器将根据模板自动创建一个函数,该函数会使用正确的数据类型完成交换变量值的任务。接下来我们一起来完成一个示例程序,同时我们将尝试创建一个这样的函数模板。
#include#include //函数模板的定义与原型写在一起,不然会出现各种错误 template void swap(T &a, T &b) { T temp= a; a = b; b = temp; } int main(){ int i1 = 100; int i2 = 200; std::cout<< "交换前,i1 = " << i1 << ",i2 = " << i2 << std::endl; swap(i1, i2); std::cout<< "交换后,i1 = " << i1 << ",i2 = " << i2 << std::endl; std::string s1 = "啪啪啪"; std::string s2 = "呸呸呸"; std::cout<< "交换前,s1 = " << s1 << ",s2 = " << s2 << std::endl; swap(s1, s2); std::cout<< "交换后,s1 = " << s1 << ",s2 = " << s2 << std::endl; return 0;}
结果:
交换前,i1 = 100,i2 = 200交换后,i1 = 200,i2 = 100交换前,s1 = 啪啪啪,s2 = 呸呸呸交换后,s1 = 呸呸呸,s2 = 啪啪啪请按任意键继续. . .
需要注意的地方:
在创建模板时,还可以用template<typename T>来代替template<class T>,它们的含义是一样一样的。
注意,template<class T>中的class并不意味着T只能是一个类。 再强调一次,不要把函数模板分成原型和实现两个部分。如果编译器看不到模板的完整代码,它就无法正确地生成代码。所得到的出错信息从不知所云”到“胡说八道”什么样都有。为了明确地表明swap()是一个函数模板,还可以使用swap<int>(i1,i2)语法来调用这个函数。这将明确地告诉编译器它应该使用哪一种类型。
如果某个函教对所有数据类型都将进行同样的处理,就应该把它编写为一个模板。 如果某个函数对不同的数据类型将进行不同的处理,就应该对它进行重载。