第九章标准模板库(STL)系统软件为计算机使用提供最基本的功能,可分为操作系统和支撑软件,其中操作系统是最基本的软件。系统软件是负责管理计算机系统中各种独立的硬件,使得它们可以协调工作。系统软件使得计算机使用者和其他软件将计算机当作一个整体而不需要顾及到底层每个硬件是如何工作的。1.操作系统是一管理计算机硬件与软件资源的程序,同时也是计算机系统的内核与基石。操作系统身负诸如管理与配置内存、决定系统资源供需的优先次序、控制输入与输出设备、操作网络与管理文件系统等基本事务。操作系统也提供一个让使用者与系统交互的操作接口。1.1类模板有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,如下面语句声明了一个类:classCompare_int{public:Compare_int(inta,intb){x=a;y=b;}intmax(){return(xy)?x:y;}intmin(){return(xy)?x:y;}private:intx,y;};classCompare_float{public:Compare_float(floata,floatb){x=a;y=b;}floatmax(){return(xy)?x:y;}floatmin(){return(xy)?x:y;}private:floatx,y;};其作用是对两个整数作比较,可以通过调用成员函数max和min得到两个整数中的大者和小者。如果想对两个浮点数(float型)作比较,需要另外声明一个类:显然这基本上是重复性的工作。C++在发展的后期增加了模板(template)的功能,提供了解决这类问题的途径。可以声明一个通用的类模板,它可以有一个或多个虚拟的类型参数,如对以上两个类可以综合写出以下的类模板:templateclassnumtype//声明一个模板,虚拟类型名为numtypeclassCompare//类模板名为Compare{public:Compare(numtypea,numtypeb){x=a;y=b;}numtypemax(){return(xy)?x:y;}numtypemin(){return(xy)?x:y;}private:numtypex,y;};classCompare_int{public:Compare_int(inta,intb){x=a;y=b;}intmax(){return(xy)?x:y;}intmin(){return(xy)?x:y;}private:intx,y;};将此类模板和前面第一个Compare_int类作一比较,可以看到有两处不同(1)声明类模板时要增加一行:templateclass类型参数名(2)原有的类型名int全都换成了虚拟类型参数名numtype。当建立类对象时,如将实际类型指定为int型,编译器就会用int取代所有的numtype,如果指定为float型,就用float取代所有的numtype。这样就实现一类多用。由于类模板包含类型参数,因此又称为参数化的类。如果说类是对象的抽象,对象是类的实例,则类模板是类的抽象,类是类模板的实例。利用类模板可以建立含各种数据类型的类。具体的做法是:Compareintcmp(4,7);即在类模板名之后在尖括号内指定实际的类型名,在进行编译时,编译系统就用int取代类模板中的类型参数numtype,这样就把类模板具体化了,或者说实例化了。这时Compareint就相当于前面介绍的Compare_int类。在声明了一个类模板后,怎样使用它?怎样使它变成一个实际的类?先回顾一下用类来定义对象的方法:Compare_intcmp1(4,7);//Compare_int是已声明的类用类模板定义对象的方法与此相似,但是不能直接写成:Comparecmp(4,7);//Compare是类模板名Compare是类模板名,而不是一个具体的类,类模板体中的类型numtype并不是一个实际的类型,只是一个虚拟的类型,无法用它去定义对象。必须用实际类型名去取代虚拟的类型。例1声明一个类模板,利用它分别实现两个整数、浮点数和字符的比较,求出大数和小数。源码参见9-1.cpp运行结果如下:7istheMaximumoftwointegers.3istheMinimumoftwointegers.93.6istheMaximumoftwofloatnumbers.45.78istheMinimumoftwofloatnumbers.aistheMaximumoftwocharacters.AistheMinimumoftwocharacters.还有一个问题要说明:上面列出的类模板中的成员函数是在类模板内定义的。如果改为在类模板外定义,不能用一般定义类成员函数的形式:而应当写成类模板的形式:numtypeCompare::max(){return(xy)?x:y;}templateclassnumtypenumtypeComparenumtype::max(){return(xy)?x:y;}}归纳以上的介绍,可以这样声明和使用类模板:①先写出一个实际的类。由于其语义明确,含义清楚,一般不会出错。②将此类中准备改变的类型名(如int要改变为float或char)改用一个自己指定的虚拟类型名(如上例中的numtype)。③在类声明前面加入一行,格式为:templateclass虚拟类型参数如:templateclassnumtype//注意本行末尾无分号classCompare{…//类体};(4)用类模板定义对象时用以下形式:类模板名实际类型名对象名;类模板名实际类型名对象名(实参表列);如:Compareintcmp;Compareintcmp(3,7);(5)如果在类模板外定义成员函数,应写成类模板形式:templateclass虚拟类型参数函数类型类模板名虚拟类型参数∷成员函数名(函数形参表列){…}说明:(1)类模板的类型参数可以有一个或多个,每个类型前面都必须加class,如:templateclassT1,classT2classsomeclass{…};在定义对象时分别代入实际的类型名,如:someclassint,doubleobj;(2)和使用类一样,使用类模板时要注意其作用域,只能在其有效作用域内用它定义对象。(3)模板可以有层次,一个类模板可以作为基类,派生出派生模板类。1.2函数模板案例1利用重载函数求绝对值:#includeiostream.h#includemath.hintf(inti){returni0?i:-i;}//函数重载longintf(longinti){returni0?i:-i;}//函数重载doublef(floati){returni0?i:-i;}//函数重载voidmain(){inta;longintb;floatc;//声明变量cinabc;cout整型:f(a)长整型:f(b)浮点型:f(c)endl;}#includeiostream.h#includemath.hclassABS//求绝对值{public:intf(inti){returnabs(i);}//函数重载longintf(longinti){returnlabs(i);}//函数重载doublef(floati){returnfabs(i);}//函数重载};voidmain(){ABSn;//声明对象inta;longintb;floatc;//声明变量cinabc;cout整型:n.f(a)长整型:n.f(b)浮点型:n.f(c);}求绝对值方法二:templatetypenameTTabs(Tvalue){returnvalue0?value:-value;}方法三利用函数模板,求绝对值的函数只要声明一个函数模板:voidmain(){inta;longintb;floatc;//声明变量cinabc;cout整型:abs(a)长整型:abs(b)浮点:abs(c);}第一次使用函数模板abs()时,实参为整数,由此可以推导出函数模板中的参数类型T为整型,函数的返回值也是整型。第二次调用abs()时实参为长整型,由此推导出函数模板中的参数类型T为长整型,函数的返回值为长整型。在主程序中可以这样使用函数模板:利用函数模板,可以建立一个具有通用功能的函数,支持不同的函数参数和返回值,达到减少代码书写量的目的。函数模板的定义形式如下:templateclassT返回值类型函数名(参数表){函数体}类型形参T代表在函数模板中要使用的通用类型,在该函数的调用过程中,T被实参的类型具体化。关键词class或typename与T一起说明用户定义的数据类型4.1.2函数模板的定义与使用函数模板实际上是定义了一类函数,对有些参数或数据成员的数据类型并不具体指定,而是作为模板的参数。等到使用模板时再根据实参的数据类型来确定模板参数的类型,得到模板的实例,称为模板的实例化。例如:templatetypenameTTabs(Tvalue){returnvalue0?value:-value;}若使用模板时:abs(5);//将模板参数的类型实例化为整型abs(-3.8);//将模板参数的类型实例化为实型函数模板实例化后生成的函数称为模板函数。在程序中可用不同类型的实参来调用同一个函数,减少了代码的书写。#includeiostream.htemplateclassT//函数模板(两数交换)voidswap(T&x,T&y){Ttemp=x;x=y;y=temp;}templateclassT//函数模板(冒泡排序)voidsort(T*v,intn)//参数中有参数化类型的参数,也有普通类型的参数{for(inti=1;in;i++)for(intj=0;jn-1;j++)if(v[j]v[j+1])swap(v[j],v[j+1]);//调用函数模板实例化后生成的模板函数}案例2编写冒泡排序的函数模板并实现排序。templateclassT//print函数模板(显示输出)voidprint(T*v,intn){for(inti=0;in;i++)coutv[i];coutendl;}voidmain(){shorta[10]={22,11,44,66,88,99,0,33,55,77};cout排序前:;print(a,10);sort(a,10);//对整型数据排序cout排序后:;print(a,10);chars[]=zcpkvrehaq;cout排序前:;print(s,10);sort(s,10);//对字符型数据排序cout排序后:;print(s,10);}第二部分泛型编程原理模板的进一步讨论泛型程序设计面向过程->基于对象->面向对象->泛型1.将程序写得尽可能通用2.将算法从特定的数据结构中抽象出来,成为通用的C++的模板为泛型程序设计奠定了关键的基础STL是泛型程序设计的一个范例18若一个程序的功能是对某种特定的数据类型进行处理,则可以将所处理的数据类型说明为参数,以便在其他数据类型的情况下使用。2.1模板概述通过模板可以产生类或函数的集合,使它们操作不同的数据类型,从而避免需要为每一种数据类型产生一个单独的类或函数。模板用于表达逻辑结构相同,但具体数据元素类型不同的数据对象的通用行为。2.1模板概述模板把函数或类要处理的数据类型参数化,表现为参数的多态性使得程序(算法)可以从逻辑功能上抽象,把被处理的对象(数据)类型作为参数传递C++提供两种模板机制:•函数模板•类模板模板函数模板类模板对象模板、类