到目前为止,我们已经介绍了两种C++程序设计范型,即:
- 按照面向过程式范型把程序划分成不同的函数
- 按照面向对象式范型把代码和数据组织成各种各样的类并建立类之间的继承关系。
泛型编程
泛型编程技术支持程序员创建函数和类的蓝图(即模板,template),而不是具体的函数和类。
这些模板可以没有任何类型:它们可是处理的数据并不限于某种特定的数据类型。
当程序需要用到这些函数中的某一个时,编译器将根据模板即时生成一个能够对特定数据类型进行处理的代码版本。
泛型编程技术可以让程序员用一个解决方案解决多个问题。
在泛型编程技术里,我们任何需要编写自己的函数和类,但不必限定于它们所使用的数据类型。
只需要使用一个占位符(通常用字母T表示),然后用这个占位符来编写函数。
当程序是需要这段代码时,你提供数据类型,编译器将根据你的模板即时生成实用的代码。
简单的说,编译器把模板里的每一个T替换为所提供的数据类型。
以下代码定义了一个名为foo()的函数模板:
template <class T>
void foo(T param)
{
//do something
}
注意:
- 第一行代码里,在尖括号里有一个class T,用来告诉编译器:字母T将在接下来的函数里代表一种确定的数据类型。
- 关键词class并不意味着这是个类,只是一种约定俗成的写法。
例子:
交换两个变量的值是一种几乎所有的程序都需要用到的基本操作。因为这种交换如此常见,所以把它编写为一个函数是个好主意。
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
简单分析下,如果我们想用这个函数来交换两个double类型的变量的值,我们应该怎么办?
没错,我们可以再增加一个swap(double &a, double &b)函数,因为C++支持函数重载。
我们发觉,我们不得不为要交换的每一种数据类型反复编写同样的代码。
这正是函数模板大显身手的地方,你用不着为每一种数据类型分别编写一个函数,只要告诉编译器你已经为此准备好了一个模板就行了。
这样子你再使用swap()函数时,编译器将根据模板自动创建一个函数,该函数会使用正确的数据类型完成交换变量值的任务。
完整实例:
#include <iostream>
#include <string>
template <class T>
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;
}