1 泛型思维
我们在解决一些特殊问题的时候,常常会将其中的某些因素或结构泛化推广到一般的情况,然后找到求解此类问题的一般化方法,即从特殊到一般的归纳思维;而对于特殊问题求解,则只需指定其具体的因素或结构形式,然后借助一般化方法进行求解,即从一般到特殊的演绎思维。泛型思维,本质上是这种先归纳后演绎的思维。
所谓泛型,字面含义是泛类型化或类型泛化,也就是把函数或者类中的数据类型或者对象类型单独提取出来作为一个参变量对待,从而使函数或者类具有更强的通用性。利用泛型思维编写程序描述问题求解思路,即泛型编程(Generic Programming),需要做归纳方向的泛化描述和演绎方向的具象应用两件事情:
1.1 泛化描述:在数据类型参数泛化的前提下描述通用的问题求解思路;
1.2 具体化应用:在通用问题求解思路的基础上指定具体的数据类型,从而产生具体问题的求解思路,然后,使用具体问题求解思路实现问题求解。
此外,C++语言基于模板机制实现了常用的一些算法和数据结构,形成了一个具有工业级强度、健壮可靠的泛型程序库,称为标准模板库(Standard Template Libarary), 是我们进行泛型编程最可依赖的基础。
2 数据类型泛化:定义模板
C++支持泛型编程,它提供了模板机制来支持数据参数泛化,包括函数模板和类模板,其中函数模板用于支持过程化问题求解思路的泛化,类模板用于支持面向对象问题求解思路的泛化。
根据模板产生一个具体函数和类的过程,称们称为模板实例化或者具像化。
2.1 函数模板
如有以下三个函数:
int sum(int a,int b);
double sum(double a,double b);
float sum(float a,float b);
不难看出,这三个sum函数具有一个统一的模式:
类型 sum(a 类型, b 类型);
如果将这个统一模式中的数据类型提取出来作为一个可变参数,则我们就不需要为每种数据类型重载一个sum函数,而只需要定义如下一个函数模板:
template<typename T> //告诉编译器,T是一个数据类型参数
T sum (T a, T b) { return a+b; }
有了模板函数,便可以实例化一个具体的函数:
int sum (int a, int b) { return a+b; }
函数模板定义与实例化可用一个实例来进行说明:
#include <stdio.h>
#include <conio.h>
template<typename T>
T max(const T arr[], int size) {
T maxElem=arr[0];
for (int i=0;i<size;i++)
if(arr[i]>maxElem) maxElem=arr[i];
return maxElem;
}
int main(){
int a[] = {1,2,4,8,7};
int b = max(a, sizeof(a)/sizeof(int));
printf("最大数组元素:%d",b);
getch();
return 0;
}
//函数模板也可显示实例化:template int max<int>(const int[],int);
运算结果:
最大数组元素:8
2.2 类模板
与函数模板类似,很多时候两个类或者多个类功能相同而数据类型有区别,此时就可以通过类模板把这些类的类型参数泛化,建立统一的类描述。语法如下:
template<class T, ... , int size, ...)
class Array {...}
如有类模板定义:
template<class T=int)
class Array {...}
有了类模板定义,然后可以隐式实例化一个具体的类:
Array<double>doubleArr(10);
或者显式实例化:
template class Array<double>;
应该可以这样说,泛化数据类型是数据类型从基本数据类型到结构体类型再到类类型的另一个层面的抽象;而泛型编程思维是相对于面向过程、面向对象的更高层面的一种抽象。