![算法设计与问题求解(第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=1739535641-K6XCIBpTTsRWmx5soXt6YZ0g5pRSnmeX-0-2e53e436723ee290f8a434eb408ddbe3)
函数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=1739535641-6m4HfBTofi3HE8QbCm4oc3y29iREecD9-0-f79a955ac7d38f1f738a196d8dd0d83b)
例如,下面代码定义了一个模板,它返回两个对象中较大的一个。
程序2-10 取较大值的函数模板
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_59_46655_l.jpg?sign=1739535641-bTVO251EbqkR98IykhIr31ZYLROn8dZl-0-690dae4ed4144c637544bb190dd0e83e)
程序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=1739535641-JD9Wj6Pbi6MstRDxCDmef272HnrWvQta-0-2596bd1cb90b54024ee175b9776e2ecd)
例如,调用GetMax函数比较两个int类型的整数可以这样写:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_471_l.jpg?sign=1739535641-BW8g594asIeBVPdvg3YbPoP9BACCktsm-0-2667a784556e1b7df4495c8b168b96e9)
在编译时,GetMax中所有GenericType 出现的地方都用int 来代替,并构造一个新函数,这个过程称为模板的“特化”。程序2-11演示了函数模板的定义和使用。
程序2-11 函数模板定义和使用示例
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_1663_l.jpg?sign=1739535641-se9PBP0w1YPztxlqsM217eHxPrVQDuBC-0-c4b811be5fd22ad70cd43b969d67004d)
注意:为了简洁起见,人们一般用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=1739535641-NqG9iHIn2SYl6CQcqPUkiWYvuaHPTCPZ-0-a838429ef33637806f815f47966930e6)
template是声明模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个。例如:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_42824_l.jpg?sign=1739535641-ZDPd4k9joBqqaHR3I7i9fSILZPpnNOvH-0-298f4ec0faa3f2c2ed1b2649bf0ec0a1)
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_61_48268_l.jpg?sign=1739535641-usTEVFk1IgDj1NwWzneHIE9HnsaGFFTm-0-283b406dbbcc633280d82f666b421843)
上面定义的类可以用来存储两个任意类型的元素组成的有序对。例如:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_61_54476_l.jpg?sign=1739535641-PyH8orxXIBWlnbCd3EPwb9mPaTaQYCbe-0-19ae4aa8fc8060d3a43637a2aa1cfeed)
分别定义了两个类对象:一个存储两个整型数据115和36,另一个存储整数和浮点数对3和2.18。