![算法设计与问题求解(第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=1738838878-VDIihr10HfoBOLhoq0hpb2vWz5E2PQkn-0-76f6dda487e3939b8929c6d460aee096)
函数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=1738838878-w5Y32KzHPjC6UUvfB1V8wij0VDe4bTYu-0-2bcc6db4771ec9a0ce9a81780af3a0f2)
例如,下面代码定义了一个模板,它返回两个对象中较大的一个。
程序2-10 取较大值的函数模板
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_59_46655_l.jpg?sign=1738838878-UWftV37rnyUMaW87KYPEB6sMiE0ToiyQ-0-9b676f3d8f429779164241b2e1928c55)
程序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=1738838878-K8mld6bdDhxLXIy2fCpdlQ7YZb0LVszs-0-59f9003414d4aa5d70b7f564634f7189)
例如,调用GetMax函数比较两个int类型的整数可以这样写:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_471_l.jpg?sign=1738838878-txr993Ka973lGfUL1Gt5SHHg1zs2T8oB-0-4d7aa2919ed1b4202713bfe1deffb71c)
在编译时,GetMax中所有GenericType 出现的地方都用int 来代替,并构造一个新函数,这个过程称为模板的“特化”。程序2-11演示了函数模板的定义和使用。
程序2-11 函数模板定义和使用示例
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_1663_l.jpg?sign=1738838878-OpuO6n0CjOWXip7wWv0lTPAXO2JzTS4N-0-9fe81cea0b707780f03bc005a9e11766)
注意:为了简洁起见,人们一般用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=1738838878-NAU4cumGBze2egu6gSQYGk4eWBtrCoaZ-0-85f0770821f8b0095436205ee76b2173)
template是声明模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个。例如:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_42824_l.jpg?sign=1738838878-zSVPAWFv9G0IT81qmGw5R3qtPAE7hYzz-0-8b0921e7c2e46e841b34960622a8ff30)
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_61_48268_l.jpg?sign=1738838878-WijFt06CB43S3pI6dV0ga6foq1ibn6Qy-0-7b897438a97b3ec91fcf6fe1a422d0df)
上面定义的类可以用来存储两个任意类型的元素组成的有序对。例如:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_61_54476_l.jpg?sign=1738838878-woUUtuXzHAu6NISurltPeCXwWAGZATqD-0-06258fb370993a7be2e88093a09d46e1)
分别定义了两个类对象:一个存储两个整型数据115和36,另一个存储整数和浮点数对3和2.18。