![算法设计与问题求解(第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=1739287690-5MoQgHsG9V7AcH4IfIhl359T9K3Uoszm-0-815f3f15ecb4f994d047a7e4e7b1d371)
函数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=1739287690-j4j3nvcYtmwPPcYUr2nPYzqyDIH5i1Pq-0-7c0d19ed79ccd0fa583733ea4d37cda9)
例如,下面代码定义了一个模板,它返回两个对象中较大的一个。
程序2-10 取较大值的函数模板
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_59_46655_l.jpg?sign=1739287690-GAbV9rPWZVNruwCLNNjm6AtE9biyfrDw-0-4d20f3a9c46273edff8a0ef0c422de7f)
程序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=1739287690-CkE3Ps7EL1p1IfY6UusCSh4gyoZZQVaz-0-62df1ab66bb6d08176645b04664ccff2)
例如,调用GetMax函数比较两个int类型的整数可以这样写:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_471_l.jpg?sign=1739287690-YULPXAiMSkD4cGL18zRxkHYPpeTu4sLx-0-7c33b111a6d6bde49777a3d6ea60db97)
在编译时,GetMax中所有GenericType 出现的地方都用int 来代替,并构造一个新函数,这个过程称为模板的“特化”。程序2-11演示了函数模板的定义和使用。
程序2-11 函数模板定义和使用示例
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_1663_l.jpg?sign=1739287690-Q5syWmUHndwjhWpdn4UYT2HvVZlHEQm2-0-21ae3724e5435a237cba393e2801ff6c)
注意:为了简洁起见,人们一般用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=1739287690-xjIEeYEW2ZICPNAeF4mPNK89x0oeDOX9-0-98ad9c2ed16fd9b3b734cc2d52a7b1a3)
template是声明模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个。例如:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_60_42824_l.jpg?sign=1739287690-xrnpQrAIUazduC3kzSv1ncGEzPOwaHSP-0-9290d2c20dd90e94b4053b8983a28a04)
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_61_48268_l.jpg?sign=1739287690-2pAEjrntKLuINb2mgm2pNuo2jnjiHEjX-0-22e22b6c38fe9bb2688ea61da7789904)
上面定义的类可以用来存储两个任意类型的元素组成的有序对。例如:
![](https://epubservercos.yuewen.com/9BC028/17545850807267206/epubprivate/OEBPS/Images/cutq_61_54476_l.jpg?sign=1739287690-DASBYPDMnolTKiURdjq5guSFYP7Erod4-0-6efc7db5b85198b5aa6a99dec68fe13f)
分别定义了两个类对象:一个存储两个整型数据115和36,另一个存储整数和浮点数对3和2.18。