ImageVerifierCode 换一换
格式:DOCX , 页数:14 ,大小:26.68KB ,
资源ID:4283575      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/4283575.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(容器模板之类的.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

容器模板之类的.docx

1、容器模板之类的【转】 C+ 概念辨析4STLC+模板-STL 容器,算法,迭代器 总结 2011-05-28 10:57转载自 我们认识啊最终编辑 zhengaoly1. 什么是模板 模板定义:模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数,从而实现了真正的代码可重用性。 我们知道,C+ 是一种“强类型”的语言,也就是说一个变量,编译器必须确切的知道它的类型,而模板就是构建在这个强类型语言基础上的泛型系统。 2. 模板的语法模板函数 template 函数定义 模板类 template class . 模板的参数可以是类型,或者是一个 int 型的值(或者可以转换

2、为int 型的,比如 bool)。 3. 模板的使用模板库只能通过头文件库的形式来提供显式类型参数:对于模板函数,在函数名后添加 。 例如:int z=max ( x, y ); 对于模板类,在类后添加 隐式类型参数:对于模板函数,如果类型参数可以推导,那么可以省略类型参数表,举个例子: template T max( T a, T b ) return a b ? b : a; 这个 max 函数就是一个模板函数,它可以传入一个 “类型”的参数,以便实现任意类型求最大值的效果。假设我们这样使用它: int x=5, y=10; int z=max ( x, y ); 这时候发生了什么呢?我们

3、传入的“类型参数”是int,因此编译器在编译这段代码时会使用 int 来构造一个新函数: int max( int a, int b ) return a b ? b : a; 后面的事就和编译普通的函数一样了,C+编译器继续使用强类型系统编译这个函数,由强类型系统来检查这个函数是否正确。这个过程叫做模板的“特化”,它发生在编译期,当编译器发现模板函数、模板类被使用(注意,不是定义)的时候进行的。这个系统实际上比较像宏,但是比宏更为智能。很明显,编译器必须知道模板如何特化这个函数,因此模板函数的实现,必须在“使用点”之前,因此模板库只能通过头文件库的形式来提供。/更为准确的解释 C+ Prim

4、er 3 10.5C+支持两种模板编译模式包含模式Inclusion Model 和分离模式Separation Mode。包含模式: 像内联函数那样将模板的说明和定义全部放在头文件中.分离模式:将模板说明放在头文件中,但是将模板实现放在c文件中,但是需要加export关键字,告诉编译器在生成被其他文件使用的函数模板实例时可能需要这个模板定义。可见使用包含模式比较简洁,所以推荐使用包含模式,将模板的说明和定义全部放在头文件中发布。除非出于软件商业化目的,不希望暴露模板定义代码给用户,需要采用分离模式。4. 模板的类型推导根据用户传送过来的行参推导对于函数,编译器是知道传入参数的类型的,比如上面

5、的max,max ( x, y ),由于第一个参数 x 是 int 类型的,那么 ? 这里需要填写什么呢? 我们可以很明显的推断出应该是 int,否则,后面的强类型系统将无法编译这个函数。编译器同样知道 x 的类型,因此它也能推导出“类型参数”,这时候我们调用时就可省略模板参数了。这个推导是按顺序来的,因此如果上面的 y 是其他类型,? 仍然会被推导为 int,如果y无法隐性转换为int,强类型编译时就会报错。 5. 类型推导的隐式类型转换 在决定模板参数类型前,编译器执行下列隐式类型转换: 左值变换 修饰字转换 派生类到基类的转换 见C+ Primer(注2,P500)对此主题的完备讨论。

6、简而言之,编译器削弱了某些类型属性,例如我们例子中的引用类型的左值属性。举例来说,编译器用值类型实例化函数模板,而不是用相应的引用类型。 同样地,它用指针类型实例化函数模板,而不是相应的数组类型。 它去除const修饰,绝不会用const类型实例化函数模板,总是用相应的非const类型,不过对于指针来说,指针和 const 指针是不同的类型。 底线是:自动模板参数推导包含类型转换,并且在编译器自动决定模板参数时某些类型属性将丢失。这些类型属性可以在使用显式函数模板参数申明时得以保留。 6. 模板的实例化,特化函数模板实例化:函数模板指定了实际类型或值构造出独立的函数的过程,称为实例化,即模板的

7、使用过程。模板的实例化可以通过隐式推导实现,也可以通过显示指定实现。特化:我们并不总是能够写出对所有可能被实例化的类型都是最合适的函数模板在某些情况下,我们可能想利用类型的某些特性来编写一些比模板实例化的函数更高效的函数,这时,就为某种类型,显式定义模板的实现,成为显式特化,所以模板特还还是模板行为的定义过程。#include / const char* 显式特化定义了max的字符串实现typedef const char *PCC;template PCC max( PCC s1, PCC s2 ) return ( strcmp( s1, s2 ) 0 ? s1 : s2 );类模板特化和

8、部分特化7. 仿函数 仿函数这个词经常会出现在模板库里(比如 STL),那么什么是仿函数呢? 顾名思义:仿函数就是能像函数一样工作的东西,请原谅我用东西这样一个代词,下面我会慢慢解释。 void dosome( int i ) 这个 dosome 是一个函数,我们可以这样来使用它: dosome(5); 那么,有什么东西可以像这样工作么?答案1:重载了 () 操作符的对象,比如: struct DoSome void operator()( int i ); DoSome dosome; 这里类(对 C+ 来说,struct 和类是相同的) 重载了 () 操作符,因此它的实例 dosome 可

9、以这样用 dosome(5); 和上面的函数调用一模一样,不是么?所以 dosome 就是一个仿函数了。 实际上还有答案2: 函数指针指向的对象。 typedef void( *DoSomePtr )( int ); typedef void( DoSome )( int ); DoSomePtr *ptr=&func; DoSome& dosome=*ptr; dosome(5); / 这里又和函数调用一模一样了。 当然,答案3 成员函数指针指向的成员函数就是意料之中的答案了。 8. 仿函数的用处 不管是对象还是函数指针等等,它们都是可以被作为参数传递,或者被作为变量保存的。因此我们就可以把

10、一个仿函数传递给一个函数,由这个函数根据需要来调用这个仿函数(有点类似回调)。 STL 模板库中,大量使用了这种技巧,来实现库的“灵活”。 比如: for_each, 它的源代码大致如下: template void for_each( Iterator begin, Iterator end, Fucntor func ) for( ; begin!=end; begin+ ) func( *begin ); 这个 for 循环遍历了容器中的每一个元素,对每个元素调用了仿函数 func,这样就实现了 对“每个元素做同样的事”这样一种编程的思想。 特别的,如果仿函数是一个对象,这个对象是可以有

11、成员变量的,这就让 仿函数有了“状态”,从而实现了更高的灵活性。模板用法:定义、使用 示例#include using namespace std;template class testpublic: test(); test(); int gX();template test:test()template test:test()template int test:gX() cout sizeof(A)endl; cout sizeof(B)endl; return 0;int main ( void )test x;x.gX();return 0;/List.h/#include templ

12、ateclass Listpublic:List();List();void Add(T&);void Remove(T&);T* Find(T&);void PrintList();protected:struct NodeNode* pNext; T* pT;Node* pFirst;templateList:List()pFirst = 0;templatevoid List:Add(T& t)Node* temp = new Node;temp-pT = &t;temp-pNext = pFirst;pFirst = temp;templatevoid List:Remove(T& t

13、)Node* q = 0;if(*(pFirst-pT) = t)q = pFirst;pFirst = pFirst-pNext; else for(Node* p = pFirst;p-pNext;p = pNext)if(*(p-pNext-pT) = t)q = p-pNext;p-pNext = q-pNext;break;if(q) delete q-pT;delete q;templateT* List:Find(T& t)for(Node* p = pFirst;p;p = p-pNext)if(*(p-pT) = t)return p-pT;return 0;template

14、void List:PrintList()for(Node* p = pFirst;p;p = p-pNext)coutpT) ;coutendl;templateList:List()Node* p;while(p = pFirst)pFirst = pFirst-pNext;delete p-pT;delete p;/List. c/#Include list.hvoid main()ListfloatList;for(int i = 1;i7;i+)floatList.Add(*new float(i+0.6);floatList.PrintList();float b = 3.6;fl

15、oat* pa = floatList.Find(b);if(pa)floatList.Remove(*pa);floatList.PrintList();Visual C+的模板和泛型如何配合使用本篇教程来源于 完全教程网 原文链接:我将演示模板和泛型在何种情况下能配合使用,在何种情况下不能配合使用,并指明在 Visual C+ 2005 下当前模板实现方式的缺陷,以此来结束这一系列有关在 Microsoft .NET Framework 中进行泛型编程的专栏。我选择通过讨论将标准模板库 (STL) 引入 .NET 的过程中进行的工作,来介绍这份材料。首先,我将回顾 STL 的基本元素,这样

16、所有人都将站在同一起跑线上。STL 的 CAI有三个主要元素可用于标准模板库的设计:容器、算法和迭代器 (CAI)。顺序容器STL 矢量vector 和 List 类表示顺序容器。顺序容器保存第一个元素、第二个元素等等,直到最后一个元素。用程序来表示的函数参数列表通常作为包含字符串类型的元素的矢量来实现。例如:以下是引用片段:vector paramlist;关联容器Map 和 Set 类表示关联容器。关联容器支持快速查找。例如,Map 表示键/值对:键用于查找,而值表示存储和检索的数据。要表示电话号码簿,您需要声明一个带有字符串键和整数值的 Map:以下是引用片段:map phonedir;

17、 多重映射可使单一键支持多个电话条目。泛型算法STL 还提供一个算法集,其中包含用于查找、排序、替换和合并的算法(可以对容器进行运算)。这些算法称为泛型算法,因为它们独立于正在其上进行运算的元素类型(例如整型、双精度类型或字符串类型)和包含元素的容器类型(例如无论容器是矢量、列表还是内置数组)。泛型算法通过直接在容器上进行运算来实现容器独立性。程序不向算法传递容器,而是向它们传递标记了要通过其进行迭代的元素范围的迭代器对 (第一个, 最后一个,其中最后一个元素充当终结标志或一个标记,以表明元素集之后的元素并将停止算法:以下是引用片段:sort( paramlist.begin(), param

18、list.end() ); 此处,begin() 和 end() 是所有 STL 容器提供的方法,会将迭代器返回到元素集第一个元素和位于末尾元素之后的元素。例如,看一下以下声明序列:以下是引用片段:void f() int ia4 = 21, 8, 5, 13 ; vector ivec( ia, ia+4 ); /将 ivec 初始化为 ia. list ilist( ia, ia+4); /将 ilist 初始化为 ia . / . 注意:ia+4 实际指向最后一个元素 (13) 之后的地址。使用 STL 的人们最初可能被这种区别所蒙蔽,例如,传递截止到 ia+3 处,这将使元素 13 不

19、能包括在一系列值中。迭代器迭代器提供了一种统一且独立于类型的方式来访问、遍历和比较容器的元素。迭代器是一种类抽象,可以提供统一的指针操作(例如 +、-、*、=、!=),无论容器是内置数组、列表还是其他任何一致的 STL 容器:以下是引用片段:void f() / 每次调用相同的泛型算法. sort( ia, ia+4 ); sort( ivec.begin(), ivec.end() ); sort( ilist.begin(), ilist.end() ); 在每个排序调用中(共三个),结果序列理所当然是:5、8、13、21(Fibonacci 序列的第四个到第七个元素)。现在,这只是一种对

20、 STL 的理想化观点,并不能证明在正式约束和实际约束下实际可行。正式约束是指:不是所有的容器类型均支持所有算法运算。例如,Map 或 Set 不支持 random_shuffle,因为对元素进行的任何重新排序均违反容器类型,这就像将索引编入堆栈中将违反堆栈的语义特征一样。 更实际地说,通过泛型算法,使用排序或查找来获得 List 容器中的元素,比在矢量上进行同一运算更加费力。因此,List 容器类型提供了自己的比泛型算法更高效的类方法。同样,使用 List 容器类型的查找方法来查找 Map 元素,比使用查找算法(通过向算法传递 Map 的开始和结束迭代器及其键)更快捷。大家可能会希望算法在所

21、有容器上的执行效果都相同,但实际上,算法更适合在 Block 容器和内置数组,而不是在 List 容器和关联容器类型上使用。实际上,当我在 Bell 实验室与 Alex Stepanov 一起工作时,他就把泛型算法称为 Block 算法。为 .NET 重新设计 STL要将 STL 合并到 .NET 中,首先要将容器作为公共语言运行库 (CLR) 类型重新实现。出于多种原因,我在本文中不会进行深入的讨论。总之,最好使容器成为引用类而不是值类。例如:以下是引用片段:/ 暂时简化声明. template ref class vector . ; template ref class map . ;在

22、本机 STL 中,所有容器都是非多态的。矢量的声明将给定实际矢量对象。示例如下:以下是引用片段:/ 本机 STL 矢量 / ivec.empty() = true / ivec.size() = 0 vector ivec; / ivec2.empty() = false / ivec2.size() = 10 vector ivec2( 10 );但是在 C+/CLI 下声明引用类型时,将定义一个跟踪句柄(矢量本身位于托管的堆中)。默认情况下,句柄将设置为 nullptr。请查看图 1。下一个设计要求是:使不支持模板的其他语言(例如 C# 和 Visual Basic?)能够使用容器。最简单

23、的策略是:使模板容器实现一个或多个系统容器接口(分到两个命名空间中),如图 2 中所示。通常,您将希望同时支持收集和泛型接口,以使当前使用收集接口的客户端能够使用您的类型。以下是声明支持两种接口的方法:以下是引用片段:template ref class vector : System:Collections:ICollection, System:Collections:Generic:ICollection . ;要实现系统收集命名空间的容器接口,还必须实现 IEnumerator 和 IEnumerator 的实例:以下是引用片段:generic ref class vector_enu

24、merator : System:Collections:IEnumerator, System:Collections:Generic:IEnumerator . ;实现系统容器接口的弊端是:虽然使得元素可用,但是无法操作 STL/CLR 类型的容器。因此,额外的设计支持还应该提供泛型阴影容器类型,以使其他语言可以使用实际的容器类型。有两个常规策略可以实现这种支持:Plauger 方式和 Tsao 方式(以两个主要设计师 P. J. Plauger 和 Anson Tsao 的姓名来命名)。可以认为 Plauger 方式提供泛型阴影类型。也就是说,您将创建阴影泛型类(可以将其称为 gener

25、ic_vector)。它包含矢量模板的副本。示例如下:以下是引用片段:generic public ref class vector_generic vector m_templ; / 哎呀. public: vector_generic( vector ); ;m_templ 声明行上的“哎呀”注释表示在 .NET 下对模板使用的约束。由于存在这种约束,您不能以泛型类型存储要求实例化的模板。这是因为,两个参数化类型功能的实例化时间不同。泛型由运行时来实例化;而模板由编译器来实例化。因此,模板可以包含泛型,而泛型不能包含模板。Plauger 方式下的解决方案为:创建一个公共泛型接口,模板和泛型

26、均通过该接口派生。有关示例,请参阅图 3。Tsao 方式下的解决方案是根据以下事实得出的:接口始终为模板容器(在特定程序集中实例化)的引用。因此,您只需提供一个接口并实现模板即可。泛型阴影类型将被消除。以下是引用片段:generic interface class vector_interface :ICollection .; template ref class vector :vector_interface, ICollection .;在任何情况下,除了那些使用程序集的人们以外,所有人都可以执行泛型实例而不是 STL/CLR 容器。这是因为,C+/CLR 下的模板不能成为公共程序集成

27、员。下一部分中讨论了此问题。模板为非公共程序集类型要使 .NET 识别类型,它需要两个元素:程序代码(表示要转换为公共中间语言 (CIL) 的类型)和元数据(描述类型的详细信息)。不幸的是,模板此时还不能通过任何一个元素提供给 .NET。与析构函数一样,模板并不是为 .NET 而存在的。.NET 仅能识别模板的具体实例; 而不能识别出它们是一种模板。例如,.NET 可以识别 vector 和 vector 的 CIL 和元数据,但是不能识别共享的模板矢量,CIL 和元数据都是该模板矢量的实例。这种不可识别性的副作用是,您不能辨别模板。也就是说,您不能询问 vector 实例:“您是模板吗?如果是,请把您的参数列表和类定义传递给我好吗?”另

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1