资源描述:
《STL泛型编程(windows编程技术).doc》由会员上传分享,免费在线阅读,更多相关内容在行业资料-天天文库。
第三篇高级编程前两篇分别介绍了VisualC++的MFC编程和VisualC#的.NET编程的基础内容,重点放在用户界面和图形绘制部分。Windows编程技术非常广泛和丰富,许多内容属于高级课题,例如:系统编程、上下文帮助、动态链接库、组件编程、面向方面的编程、服务器端编程、分布式编程、云计算等等。限于篇幅,本书只简单介绍:企业级应用必须的泛型编程、基于多核CPU的并行编程、商业应用所需的数据库编程和应用广泛的网络编程。本篇包含如下4章内容:l第21章STL泛型编程l第22章多线程与多核编程l第23章数据库编程l第24章网络编程 第21章STL泛型编程泛型编程(genericprogramming,类属编程)是一种通过模板(template)实现同一算法源代码用于不同数据类型的软件重用方法,广泛用于数据的遍历、查询、排序、添加/删除/复制/合并等操作和处理,是数据库管理和信息系统等企业级应用不可缺少的基础技术。泛型编程理论的最早实现是AlexanderStepanov和DaveMusser于1994年设计和开发出的STL(StandardTemplateLibrary,标准模板库),它成为C++标准(1998年)的一部分。源自C++的Java(1995年)和C#(2000年)语言在创建时,为了简化语法和降低复杂度,都不约而同地抛弃了C++的模板,从而不支持泛型编程。但是事实很快就证明,这样做是犯了一个非常严重的错误。所以Java于2004年9月在JavaSE5.0(JDK1.5)中开始使用(受限的)泛型技术,C#和.NET框架也于2005年11月在2.0版中引入了泛型编程。限于篇幅,本书只讨论标准C++中的STL泛型编程的基本内容。21.1概述面向过程的编程重用函数的目标代码,面向对象的编程重用类和对象的目标代码,泛型编程则重用算法的源代码。传统C++的泛型编程,仅仅局限于简单的模版技术。标准C++引入了容器(container)、迭代器(iterator)、分配器(allocator)和STL等概念和内容,才真正进入泛型编程的广阔天地。21.1.1泛型编程与过程及对象编程泛型编程和面向过程以及面向对象一起,构成混合型程序设计语言C++的三种编程范式(paradigm,范例/范型)。面向过程的编程,可以将常用代码段封装在一个函数中,然后通过函数调用来达到目标代码重用的目的,是最早使用的软件重用方法。面向对象的方法,则可以通过类的继承和对象成员的使用来实现(对象的目标)代码的重用。如果需要编写一个可用于不同数据类型的算法,可以采用的方法有:l面向过程——对源代码进行复制和修改,生成 不同数据类型版本的算法函数,调用时需要对数据类型进行手工的判断。l面向对象——可以在一个类中,编写多个同名函数,它们的算法一致,但是所处理数据的类型不同,当然函数的输入参数类型也不同,可通过函数重载来自动调用对应数据类型版本的函数。显然,这两种方法都需编写了多个算法相同的不同函数,不能做到代码重用。它们二者之间的主要差别,只是调用的方便与否。如果采用泛型编程(例如可采用以类型作为参数的传统C++的模板技术),就可以做到源代码级的重用:l泛型编程——编写以类型作为参数的一个模板函数,在调用时再将参数实例化为具体的数据类型。注意,模版的实例化,是在编译阶段完成的,属于静态性质的方法,与C/C++的宏替代方式非常相似,但是却更为安全、更易理解、且更加高效。为了实现一个,在具有不同组织结构(如数组、链表、队列、堆栈等)、含同一类型(如char、int、float、struct或class等)的数据或对象的集合(容器)上的,与具体数据类型无关的参数化通用算法(如排序、检索、复制、合并等)。光有模版是远远不够的,还需要能够表示这种集合的容器、能够在容器中遍历的迭代器、能够为算法和容器实现抽象存储的分配器、能够在不同容器之间进行转换的适配器、以及针对容器中数据集合的各种与具体类型无关的通用算法等。这些正是泛型编程的研究内容,也是STL要实现的目标。21.1.2泛型编程与STL泛型编程是一种面向算法的多态技术,STL是它的一种具体实现。1.泛型编程在计算机科学中,泛型(generic,类属)是一种允许一个值取不同数据类型(所谓多态)的技术,强调使用这种技术的编程风格被称为泛型编程。泛型编程研究对软件组件的系统化组织,目标是推出一种针对算法、数据结构和内存分配机制的分类方法,以及其他能够带来高度可重用性、模块化和可用性的软件工具。 与针对问题和数据的面向对象的方法不同,泛型编程中强调的是算法。是一类通用的参数化算法,它们对各种数据类型和各种数据结构都能以相同的方式进行工作,从而实现源代码级的软件重用。例如,不管(容器)是数组、队列、链表、还是堆栈,不管里面的元素(类型)是字符、整数、浮点数、还是对象,都可以使用同样的(迭代器)方法来遍历容器内的所有元素、获取指定元素的值、添加或删除元素,从而实现排序、检索、复制、合并等各种操作和算法。泛型编程的通用化算法,是建立在各种抽象化基础之上的:利用参数化模版来达到数据类型的抽象化、利用容器和迭代器来达到数据结构的抽象化、利用分配器和适配器来达到存储分配和转换接口的抽象化。2.STLSTL(StandardTemplateLibrary,标准模板库)是泛型编程思想的实际体现和具体实现,它是一种为泛型组件建立大型标准库的可扩展架构。STL本身,与面向对象无关,也与具体的程序设计语言无关。STL的目标是,在不损失效率的基础上,进行抽象。这里的不损失效率,是指尽最大努力来保证其所有的泛型算法是最优的,并且和手工为具体类型编写的代码具有同样的运行效率。抽象的基础是数学逻辑和冯·诺依曼计算模型(存储程序体系结构)。如果用数学语言来描述,STL的本质就是:不同的数据结构,对应于不同的地址代数结构、以及不同的地址连接方式。从数据结构的一个地址,转向下一个地址的一些列操作,就对应于迭代器。在数据结构中添加和删除地址的操作,就对应于容器。STL将容器看作是结构的泛化,它们都拥有成员,可以描述整体和局部这一现实世界事物的关键属性。STL使用了赋值的算法,要求采用面向值的语义。STL还假定对容器中的数据和对象,定义了全序。STL的主要内容是容器、泛型算法、迭代器、函数对象、分配器和适配器等6种组件。在标准C++中,STL是作为C++标准库的一部分而出现的。作为STL的基础的模板,则是C++语法的一部分。3.历史泛型程序最早出现1970年代的CLU和Ada语言中,后来被许多基于对象和面向对象的语言所采用,包括BETA、C++、D和Eiffel等。1993年C++在3.0版中引入的模版技术就属于泛型编程的范畴,1994年7月ANSI/ISOC++标准委员会通过的STL, 更是泛型编程的集大成者,它已被纳入1998年9月推出的C++国际标准之中。VisualC++从2005版开始,全面支持C++的1998年和2003年国际标准,当然也包括STL泛型编程。Java于2004年9月在JavaSE5.0(JDK1.5)中开始使用泛型技术,并且因此将从JDK1.2~1.4一直使用的Java2改名为Java5,但是为了在语法、类库和字节码上与传统的Java2兼容,Java中的泛型做出了很多牺牲,包括类型信息被擦除。所以Java中的泛型是一种受限的非完整泛型。微软于2005年11月在.NET框架2.0版、C#2.0和VisualBasic2005中也于引入了泛型编程,并在2007年11月推出的.NET框架3.5版中又增加了对STL的支持。DavidMusserAlexanderStepanov1971年,美国计算机科学家DavidMusser首先提出并推广了泛型编程的理论,但是主要局限于软件开发和计算机代数领域。1979年,苏联籍的美国计算机科学家AlexanderStepanov开始研究泛型编程,1987年他与DavidMusser一道,开发出Ada的泛型表处理库。1990年前后,Stepanov先后在贝尔实验室和HP实验室,进行泛型编程的研究和库设计,提出了STL的体系结构。1993年11月,受贝尔实验室的AndrewKoening的邀请,Stepanov在ANSI/ISOC++标准委员会的会议上,介绍了泛型编程的理论和他们的工作。Stepanov和MengLee按委员会的要求,于1994年3月提出了STL的草案。委员会提出了一些修改意见,其中最重要的是对关联容器的扩充,由Musser完成了扩充部分的实现工作。1994年7月,ANSI/ISOC++标准委员会终于通过了修改后的STL方案,并将其纳入1998年推出的C++标准之中。1994年8月,HP将Stepanov和Lee等人开发的STL,在因特网上免费发布。1995年Stepanov又到SGI工作,他与HansBoehm和MatthewH.Austern一起,为SGI开发了STL。SGI也把它免费地放在了因特网上(http://www.sgi.com/tech/stl/download.html),并提供了一个完整的在线说明文档(由Austern编写,参见网页http://www.sgi.com/tech/stl/)。鉴于AlexanderStepanov对STL的重大贡献,他被誉为STL之父。21.2容器容器(container)是装有其他对象的对象。容器里面的对象必须是同一类型,该类型必须是可拷贝构造和可赋值的,包括内置的基本数据类型和带有公用拷贝构造函数和赋值操作符的类。典型的容器有队列、链表和向量等。 在标准C++中,容器一般用模版类来表示。不过STL不是面向对象的技术,不强调类的层次结构,而是以效率和实用作为追求的目标。所以在STL并没有一个通用的容器类,各种具体的容器也没有统一的基类。容器可以视为是数组的推广,即对象的数组(广义数组),其中的元素(对象)可以用下标(索引)来访问。容器的设计有两条准则:一是在各个容器的设计中,提供尽可能大的自由度;二是使各种容器能够向用户呈现出一个公共的界面/接口。目的是,使容器的实现能达到最佳效率,同时也使用户能写出不依赖于所使用的特定容器类型的通用代码。容器的设计通常只能满足这两条中的一条,但是STL却提供了一个同时具有通用性和执行效率的解决方案。21.2.1分类标准C++的STL框架中的主要容器有序列容器和关联容器两大类,另外两大类容器分别是容器适配器和拟容器。1.序列容器序列容器(sequencecontainer,顺序容器)将一组具有相同类型T的对象,以严格的线性形式组织在一起。序列容器可以视为数组和链表的推广。STL中的序列容器有如下3种:1)vector(向量)——提供对变长序列的快速随机访问(即对第i个元素的访问时间,是与i无关的常量),对序列末尾的插入和删除操作的时间是分摊常量;(似变长数组)(对应于vector类,定义在头文件中)。2)deque(double-endedqueue,双端队列)——提供对变长序列的快速随机访问,对序列头尾的插入和删除操作的时间都是分摊常量;(似双向变长数组)(对应于deque类,定义在头文件中)。3)list(表)——提供对变长序列的线性时间访问(O(N),N为序列的当前长度),但是在序列的任意位置的插入和删除操作均为常量时间。(似双向链表)(对应于list类,定义在头文件中)。 2.关联容器关联容器(associativecontainer,联合容器)的特点是(键)有序的,即元素是按预定义的键顺序(如升序)插入的。关联容器具有从基于键的集合中快速提取对象的能力,其中集合的大小在运行时是可变的。关联容器可以视为关联数组、映射或字典的推广,它们保存的都是值的对偶,给定了其中的一个被称为键(key)的值,就可以快速访问与其对偶的另一个被称为映射值(mappedvalue)的值。STL中的关联容器有如下4种:1)set(集合)——支持唯一键值,并提供对键本身的快速检索;例如set:{学号}。集合关联容器,对应于set类,定义在头文件中。2)multiset(多重集合)——支持可重复键值,并提供对键本身的快速检索;例如set:{姓名}(可能有同名的)。多重集合关联容器,对应于multiset类,也定义在头文件中。3)map(映射/映像)——支持唯一Key类型的键值,并提供对另一个基于键的类型T的快速检索;例如map:{(学号,姓名)}、{(电话号码,姓名)}等。映射关联容器,对应于map类,定义在