![算法设计与问题求解(第2版):计算思维培养](https://wfqqreader-1252317822.image.myqcloud.com/cover/909/32517909/b_32517909.jpg)
2.3 标准模板库
2.3.1 模板的基本概念
标准模板库(Standard Template Library,STL)可以说是基于模板(Template)而建立的。因此我们先简要介绍模板的基本概念及使用方法。
模板是实现代码重用机制的一种工具,可以实现类型参数化,即把类型定义为参数,从而实现了真正的代码可重用性。C++是一种“强类型”的语言,即编译器必须确切地知道变量的类型,而模板就是构建在这个强类型语言基础上的泛型系统。
我们先看一个示例程序。
程序2-9 整型取较大值函数
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_59_30904_l.jpg?sign=1739280832-xOwwbjoPl27YVBZlSEI1fcfTbv5MEIfS-0-2e8f4c8d41354c58f983dd2b2024b638)
函数GetMax()返回两个整数中的较大值。但是在一个实际应用程序中可能还需要处理float、long、char等类型的变量,甚至是自定义类型(如结构体)的变量。针对不同的参数类型,需要把上面代码中的数据类型修改为特定类型,然后复制到需要的地方。这种设计方法会给代码维护带来很大的困扰,如代码量增大,修改时需要对多处代码进行修改。解决这个问题的方法之一是使用模板。
模板包括函数模板(Function Template)和类模板(Class Template)两种,下面分别介绍函数模板和类模型的定义和使用。
函数模板(Function Template)用于定义和生成通用的函数,这些函数能够接受任意数据类型的参数,可返回任意类型的值,而不需要对所有可能的数据类型进行函数重载。这在一定程度上实现了宏(Macro)的作用。它们的原型定义可以是下面的任何一个。
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_59_41753_l.jpg?sign=1739280832-QFOm0k4uoojYmHuNFeesuqA9pkA2tWLq-0-3694ecf5f1794d6b15bcde1f87b243c0)
例如,下面代码定义了一个模板,它返回两个对象中较大的一个。
程序2-10 取较大值的函数模板
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_59_46655_l.jpg?sign=1739280832-OnFESwv6gAX3ZmmTHaqZ973d55TYLXEd-0-fdd096a25ea57f4254ba88db1bee3d96)
程序2-10中的第一行声明一个通用数据类型,称为GenericType。因此在其后面的函数中,GenericType成为一个有效的数据类型,被用来定义两个参数a和b,并被用于函数GetMax的返回值类型。在定义时,GenericType没有代表任何具体的数据类型。当函数GetMax被调用的时候,我们可以使用任何有效的数据类型来调用它。这个数据类型将被作为模式(Pattern)来代替函数中GenericType出现的地方。
用一个已定义数据类型来调用函数模板的方法如下:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_58685_l.jpg?sign=1739280832-lxCakkdF7KYmJipiLEwSlncjgeOZOSyK-0-89f4e3cea00881d313a5890777aa717c)
例如,调用GetMax函数比较两个int类型的整数可以这样写:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_471_l.jpg?sign=1739280832-Eyjw4T0mpO29kSjhIUKBqRkSB2ipxCLZ-0-14acfe0bc2ab56993fa56e7a0eedb0dd)
在编译时,GetMax中所有GenericType 出现的地方都用int 来代替,并构造一个新函数,这个过程称为模板的“特化”。程序2-11演示了函数模板的定义和使用。
程序2-11 函数模板定义和使用示例
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_1663_l.jpg?sign=1739280832-nefZCtz7h3v2ZL2OKCOKjrY3U1Ja56tF-0-bf6f04a94313fcb3e0923c4e372bf00a)
注意:为了简洁起见,人们一般用T代替GenericType,表示通用数据类型。
在上面的例子中,我们对同样的函数GetMax使用了两种参数类型:int 和 long,而只写了一种函数的实现,即我们写了一个函数的模板,用了两种不同的模式来调用它。
在函数模板中,如果类型参数可以推导,那么可以省略类型参数表。比如,在程序2-11中,GetMax<int>(i, j)替换为GetMax(i, j)可以得到同样的结果。因为i和j都是int类型,编译器会自动假设我们想要函数按照int进行调用。请读者自己完成验证。
类模板(Class Template)使得一个类可以有基于通用类型的成员,而不需要在类定义的时候确定具体的数据类型。原型定义如下:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_26274_l.jpg?sign=1739280832-zNoxXQXcgNwo2Byn719WALxaSOMv7cBQ-0-f33306f2420f4e990d3ef0cfc63cc35e)
template是声明模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个。例如:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_42824_l.jpg?sign=1739280832-nzUPJbwDcimTzER7nk7neR0usMsrfY0M-0-c01b75eb99ad91751d5a7b6d5b8c0da5)
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_61_48268_l.jpg?sign=1739280832-RT88kCuBMhPTOL7yoa3UMImI0o259Cnh-0-877263a3608124fe787ac4fe26c448fb)
上面定义的类可以用来存储两个任意类型的元素组成的有序对。例如:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_61_54476_l.jpg?sign=1739280832-RC1QOxDoij2Jgan78OEEIFdVDHJMvFP0-0-dcc6cc1feaa2c71af811700c14d52980)
分别定义了两个类对象:一个存储两个整型数据115和36,另一个存储整数和浮点数对3和2.18。