我们看到这个标题是不是觉得有点纳闷?我们要学习的是数据结构和,并不是某门语言。比如 C++ 就支持泛型编程,那么我们为什么还要来讨论这个呢?我们先来看看数据结构的特点:1、专注于数据元素之间的关系;2、专注于特定结构之上的算法。数据结构并不关注数据元素的具体类型!
那么如何为数据结构的学习选择合适的语言呢?我们之前有见到过 C 语言版的数据结构,也有 C++ 版的数据结构。但是从耦合性的角度来看,支持泛型编程的语言最适合数据结构的学习。所谓泛型编程便指的是不考虑具体数据类型的编程方式。对于 Swap 函数可以考虑写成泛型写法,如下
void Swap(T& a, T& b) { T t = a; a = b; b = t; }
Swap 泛型写法中的 T 不是一个具体的数据类型,而是泛指任意的数据类型,这样我们是不是就可以代码复用了,不用重复的搬砖了。泛型编程对应于 C++ 中的函数模板,它是一种特殊的函数可用不同类型进行调用。它看起来和普通函数很相似,其区别是类型可被参数化。函数模板格式如下
template < typename T > void Swap(T& a, T& b) { T t = a; a = b; b = t; }
下来我们来看看函数模板的语法规则:1、template 关键字用于声明开始进行泛型编程;2、typename 关键字用于声明泛指类型。如下图所示
我们来看看函数模板的使用:1、自动类型推倒调用;2、具体类型显示调用。具体如下
int a = 0; int b = 1; Sawp(a, b); // 自动推导 float c= 2; float d = 3; Swap<float>(c, d); // 显示调用
我们下面还是以代码为例来进行说明
#include <iostream> using namespace std; template < typename T > void Swap(T& a, T& b) { T t = a; a = b; b = t; } template < typename T > class Op { public: T process(T v) { return v * v; } }; int main() { int a = 1; int b = 2; Swap(a, b); cout << "a = " << a << ", " << "b = " << b << endl; double c = 0.01; double d = 0.02; Swap<double>(d, c); cout << "c = " << c << ", " << "d = " << d << endl; Op<int> opInt; Op<double> opDouble; cout << "5 * 5 = " << opInt.process(5) << endl; cout << "0.5 * 0.5 = " << opDouble.process(0.5) << endl; return 0; }
我们来编译看看结果,是否如我们代码所写的那样
C++ 中的类模板是以相同的方式处理不同的类型,在类声明前使用 template 进行标识;<typename T> 用于说明类中使用的泛指类型 T。类模板只能显示指定具体类型,是无法进行自动推导的;使用具体类型 <Type> 定义对象。在上面的例子中,如果我们在第39, 40行不指定具体类型时,看看会发生什么?
报了一大堆错误,最后发现是没指定具体类型所导致的。通过对泛型编程的学习,总结如下:1、模板是泛型编程理论在 C++ 中的实现;2、函数模板支持参数的自动推导和显示指定;3、类模板在使用时只能显示指定类型;它非常适用于编写数据结构相关的代码。