VC++库

作者:网络 来源:佚名 更新时间:2008-07-09 11:17:27 点击:



    大量的程序员都尽可能多地利用现有的代码。程序员经常购买那些包装成库的代码,而且许多成功的公司正是靠生产真正优秀的代码库而发展起来的,例如rogue wavesoftware (www.roguewave.com)。
    当c语言流行时,代码库就是函数库。例如,可以购买一个数学库,该库含有完成微积分和代数运算的函数。通常,可以在程序代码中使用一个包含文件来指定一个函数库,可以静态或动态地链接这个函数库。
    静态链接意味者库代码直接集成到程序中。在这种情况下,程序不依赖于其他文件,但文件的大小可能很大。动态链接意味着程序有库的版本信息,其代码存放于一个单独的文件中,这个文件称为动态链接库(dll)。只有程序运行期间调用dll中的函数时,才加载dll到内存。dll作为一个独立的实体存在于内存中,可以同时被多个程序访问。
    出现c++后,函数库转变为类库。两者的区别在于函数库只包含一系列函数,而类库是用面向对象编程的原理设计的,例如,可以为数据结构做一个类库,该库包括一个链接列表的类。如果使用一个函数库代替,那么链接列表会独立于操作它的函数。另一方面,使用类库时,链接列表和操作它的函数存在于同一个文件的同一个类中。然而,正如使用函数库一样,使用类库涉及到包含文件和链接一个静态库。
    最近,已经从类库发展到模板库。其原因是c++编译器现在已经能够处理c++模板。模板库提供了一系列优于类库的优点。要使用模板库,只要在程序中加入包含文件即可,不用链接到库,因为所有的库代码已经包含在该包含文件中了。
    这听起来不是非常高效,早期确实如此,因为每个包含有模板文件的文件都要得到一个单独的代码拷贝。因此,编译后的程序会很大。但是,为了适应模板,编译器已经优化,使得这种方法非常高效。
    vc有三个供开发者使用的库:一个类库(mfc),二个模板库(atl和stl)。
17.2.1 微软基础类库
    微软基础类库(mfc)是微软为帮助c++开发者而建立的类库,含有支持各种不同功能的许多类,包括实现复杂的数据结构、操作windows和访问数据库等。但是,是否应在服务器组件中使用mfc?回答是否定的!
    这很明智的,不要在服务器组件中使用mfc,服务器组件不能访问win 3.2,所以不需要mfc库,数据库支持最好用atl实现。
    atl支持ado和ole db,而mfc不支持。stl与mfc相比有更好的数据结构支持。即使最常用的mfc类,如cstring,在标准c库中也有等价的类。偶尔会使用mfc类,如csocket,但它也可被一种win 32 api代替。
    mfc是用来建立单独windows应用程序的,不是用于轻量的com组件。只有在与现有的使用mfc的代码接口时应使用mfc类。其他情况使用atl和stl类,这样可以使组件更小且运行得更快。
17.2.2 活动模板库
    你可以判断出活动模板库(atl)比mfc新,因为atl中有“active”这个词,另一种叫法是“微软模板库”(microsoft templete library,mtl)。
    atl用来快速、简易地创建com组件,而且只占用较少的内存,组件的关键部分是由c++模板完成的。实际上,atl的设计在模板的使用上沿用了stl。
    c++模板提供一种类型安全的方法来实现一般的接口。很幸运,微软提供了一些产生atl代码的向导,所以在建立简单组件时,不必了解模板,甚至不用知道activex的所有细节。atl另一个优点是不依靠dll,就是说在装载应用程序时,不必装载dll和静态地链接,这两项会增加对内存空间的需求。
    atl使com的开发更加容易,atl同样支持通过ole db消费者和提供者的数据访问,还有一些特殊的用途,如支持建立微软管理控制台(mmc)插件组件。
    与atl比较,mfc依赖于额外的运行期dll或静态链接,所以产生了比atl大而慢的代码。因此,在建立com组件时,如果没有用户界面,那么选择atl比mfc好。
17.2.3 标准模板库
    标准模板库(stl)对于vc++编程员来说是使用得最不充分的有用工具之一,但它是唯一一个标准的和跨平台的vc++库。
    使用stl不多的原因之一是,微软的stl文献难以理解。现在没有为vc++程序员而编写的stl书藉,由musser和sauni编写的《stl tutorial and reference guide》是一本关于stl的好书。
    stl对c++组件开发很有用,原因是包含了许多数据结构和算法。很多情况下,服务器组件的用途就是处理数据,stl非常合适这一用途。
    微软最初实现stl标准是在vc++ 4.2中,但是,这个stl实现做得很差,以致不能使用。一些人通过使用hp或sgi提供的stl实现解决这个问题。既然stl是一种iso/ansi标准,它就是跨平台的,只要编译器支持stl所要求的结构就可以。然而,微软更新的stl实现(在vc++ 5.0和6.0中的提供),比以前的stl更稳定、更容易使用。
    stl是对atl的完美补充,atl没有数据结构和算法。而且,stl和atl有相似的实现方法,即使用c++模板,所以配合得很好,而且两者都不需要链接额外的动态或静态链接库,这样就会使组件更小,使它们对dll的依赖更小。
    下面让我们对stl的关键概念做些介绍,在建立服务器组件时要用到这些概念。
    1. stl遍历器
    使用c编程时,一般使用两种方法来遍历数据结构:使用一个下标或递增一个指针,这两种方法达到相同的效果。但是编写一个通用的算法来处理不同的类型是不可能的,用stl遍历器能解决这个问题,下面的例子是最好的说明。
    下面的程序展示了两种标准c的遍历方法,最后是stl的遍历方法。该程序的任务是计算一个字符串中“t”的个数。


    使用遍历器解决了使用指针或下标时出现的问题。指针和下标依赖于数据,这些数据在内存中相邻存放,而遍历器隐藏数据,使数据结构的使用者不必了解数据存储的顺序。隐藏数据结构允许创建通用的算法,这种算法能够与各种数据结构一起工作,例如与容器一起工
作。
    为了算法的效率,stl定义了五种遍历器的类:输入、输出、前向、双向和随机访问。算法针对特定的遍历方法设计,因此具有最优的性能。
    遍历器相似于指针,移动到下一条目和前一条目分别使用操作符“ + +”和“ - -”,同样,获得一个条目的值使用操作符“ *”。
    2. stl映射
    一个映射就是一个排好序的容器,这里关心的是能够根据存储在条目中的键以尽可能快的速度检索条目,而不是关心使条目以线性的顺序存储在容器中。
    stl排序容器有set、multisetmap和multimap。set用于条目集合,map用于一个条目与另一条目的关联。由于使用双向遍历器,排序容器支持以线性顺序移动数据条目,尽管排序容器的目的是用于键访问。
    一个映射容器支持基于单独键的快速数据检索,这个键在映射中是唯一的,映射对于稀疏数据具有节省大量存储空间和减少许多计算时间的潜力,在后面的叙述中你将看到。键和值是以pair类型存储的,这个类型有两个成员:first和second。检索first返回键,检索second返回键的值。映射的遍历器就是pair类型的遍历器。
    在本章后面将看到使用映射的例子。
    3. stl 矢量
    一个矢量就是序列容器的一个例子,其他序列容器是deque和list。它们具有相似的功能,基本的区别在于性能。例如,除了在deque的开始处插入和删除的速度比在vector中快之外,一个deque与一个vector没什么区别。不同的问题要用不同的方式来访问数据。矢量能对不同长度的数据提供快速随机的访问,在此序列的末尾插入和删除时较快,而在其他在地方则比较慢。
    4. stl算法
    stl算法根据对其操作的数据结构的影响方式和相互作用进行分类。stl算法与其操作的stl数据结构的接口是stl遍历器。stl遍历器扮演了一个重要角色,因为它限制了算法怎样访问数据。许多算法接收一个函数作为其接口的一部分,这个函数的参数返回一个布尔值,表示一种情况。用函数参数可以定制算法。
    一些stl算法允许函数作为参数传递。多数情况下,这些函数完成一个比较,并且返回布尔值。例如,一个排序算法使用一个函数作为参数来比较两个值,这个函数根据某些准则比较一个值是否比另一个值小。不同的函数有不同的准则,从而导致数据以不同的顺序排列。
    更有趣的是,将一个函数对象(而不是函数)作为传递参数。函数对象可以包含状态,这种状态可以启用存在于某处的比较规则。使用的比较规则依赖于对象的状态。在本章的后面有一个排序算法的比较函数的例子,以这种方式实现。
    5. stl 算法的分类
    stl算法可分为四大类。非变异序列算法,操作不改变数据结构内容;变异序列算法则改变数据结构内容;相关排序算法能用于排序、合并和二进制查找等多种算法。最后,stl具有广义的数值算法,用于计算数据结构中的元素。
    ? 非变异序列算法:不直接改变其操作的数据结构的元素。通常,它们查找数据结构中的元素,检查序列元素的等式,计算序列元素的个数。find和count是非变异序列算法的例子,find算法在数据结构的某个范围中移动,查找第一个等于给定值的遍历器。而count算法计算数据结构中等于给定值的元素的个数。
    ? 变异序列算法:修改其操作的数据结构中的元素。这些算法在容器中拷贝、替换、转换、删除和循环移动元素。fill算法是这种算法的一个例子,它的功能是把给定值的拷贝填充到一个序列范围中的所有位置。
    ? 相关排序算法:排序、合并和查找元素。同样,能够对排好序的序列进行设置操作,merge算法是一个例子,它将两个已排序范围内的元素放到一个范围内,并且结果不发生重叠。
    广义数值算法的例子是accumulate,这个算法对数据结构内的某一指定范围的值求和。
    6. 使用算法的遍历器
    前面已经讲过,stl定义了五种遍历器的类:输入、输出、前向、双向和随机访问,算法针对特定的遍历方法设计,以确保优化性能。
    例如,find算法可以用于在各种数据结构中查找值,算法并不关心容器是一个矢量,还是一个列表,还是一个数组。唯一的条件是数据结构必须支持inputiterator,inputiterator的设计确保它支持的操作的工作效率。find算法只需要inputiterator支持的操作,因此,find算法能高效地工作。
    一些算法要求功能更强的遍历器:如sort需要随机访问遍历器(random access iterator)。提供随机访问是以降低性能为代价的,并影响其他操作,例如在容器中间插入元素的操作。
    现在已经你有充分的理论知识,下面建立一个组件。