您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > 类型安全的通用模板类
12.7类型安全的通用模板类12.7.1单链表类单向链表结点=数据结点+链指针结点可以是不同的类型总是相似的:指向一个链表结点的指针(公共特征,作为基类)1链结点:slinkstructslink{slink*next;slink(){next=0;}slink(slink*p){next=p;}}2表结点:name#includestring.hclassname:publicslink{char*s;public:name(constchar*ss){s=newchar[strlen(ss)+1];strcpy(s,ss);}//…}3单链表类:slist_baseclassslist_base{//...public:intinsert(slink*);//upcasting,可以处理不同类型的结点intappend(slink*);//upcastingslink*get();};4使用单链表voidf(constchar*s){slist_baseslb;slb.insert(newname(s));//…name*p=(name*)slb.get();//…deletep;}12.7.2扩充:链表结点exprclassexpr:publicslink{//…};voidmain(){slist_baseslb;slb.insert(newexpr);slb.insert(newname(“s1”));slb.insert(newexpr);//…expr*e1=(expr*)(slb.get());expr*e2=(expr*)(slb.get());//使用e2可能出错}12.7.3有什么问题?由于slist_base是按slink而不是name来定义对链表的操作,当对象放入链表之后,其静态类型信息也就消失了。当从链表中取出它时,需要进行强制类型转换,把链表中存放的对象转换成它原来的类型name.但是:要记住每次取出对象的具体类型是很困难的。难题:如何保证链表中的类型安全性?若用虚函数,不必进行强制类型转换,没有什么问题。但用户只能通过虚函数的动态绑定来使用基类提供的接口;若要对具体的派生类进行处理,则注定了这种异质链表(链表中可以存放不同类型的对象)不是类型安全的。12.7.4同质链表的类型安全性•同质链表:链表中只能存放相同类型的对象。•同样地,如何保证其类型安全性,即如何避免链表中插入对象与取出对象类型不一致的问题。•利用模板参数在编译时的类型检查!1.类模板IslisttemplateclassTclassIslist:privateslist_base{public:voidinsert(T*a){slist_base::insert(a);}T*get(){return(T*)slist_base::get();}//…}2.使用类模板voidf(constchar*s){Islistnameilst;ilst.insert(newname(s));//…name*p=ilst.get();//…deletep;}3.误用类模板voidf2(constchar*s){Islistnameilist;ilist.insert(newexpr);//编译时error,类型不匹配//…}小结:在Islist实现中,实际的工作仍然由slist_base来完成,而类模板只是为了防止出现不安全的类型。直观地说,类模板ilist好像是一个过滤器,不安全的类型传给它时都会被检查出来12.8容器和迭代器12.8.1容器简述什么是容器?容器就是用来装对象的东西,容器本身也是一个对象。如:数组,链表,栈,队列,集合等。他们之所以被称为“容器”就是因为他们的存在在很大程序上就是为了容纳一组别的东西。a1a2a3…例:vectorint12.8.2通过模板构造容器说明如何通过模板获得类型安全性检查(参见12.7)12.8.3迭代器迭代器:用于访问容器的东西的抽象概念,比如用于遍历链表结点的指针,用于访问数组元素的下标等等。迭代器是一个对象,它在(其他对象的)容器上遍历,每次选择容器中的一个元素,但不需要提供对这个容器的实现的直接访问。提供了一种访问元素的标准方法;通常与容器联合使用;在许多情况下,是一个“灵巧指针”;但比通常的指针运算更安全。例1:访问链表的迭代器类classslist_base_iter{slink*ce;//当前元素slist_base*cs;//当前链表public:slisk_base_iter(slist_base&s);slink*operator()();};例1:类型安全的迭代器类模板templateclassTclassIslist_iter:privateslist_base_iter{public:Islist_iter(IslistT&s):slist_base_iter(s){}T*operator()(){return(T*)slist_base_iter::operator()();}};类的完整定义:参见吕书P24012.8.4为什么使用迭代器可以提供比下标更复杂的操作方法隐藏了实现细节,比指针更易用。例1:增加了简单迭代器的intstackP718C16:IterIntStack.cpp迭代器的关键:从一个容器元素移动到下一个元素的复杂过程被抽象成就像一个指针一样。例2:更一般化:嵌套的iteratorP721:例3:容器+迭代器IterStackTemplate.hP724C16:IterStackTemplate.h12.5.6C++标准模板库STL(StandardTemplateLibrary):标准模板库STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其他一些组件的集合。这里的“容器”和算法的集合指的是世界上很多聪明人很多年的杰作。STL容器可以保存对象,内建对象和类对象。它们会安全地保存对象,并定义我们能够操作的这个对象的接口。STL算法是标准算法,我们可以把它们应用在那些容器中的对象上。这些算法都有很著名的执行特性。它们可以给对象排序,删除它们,给它们记数,比较,找出特殊的对象,把它们合并到另一个容器中,以及执行其他有用的操作。12.5.6C++标准模板库(续)STLiterator就象是容器中指向对象的指针。STL的算法使用iterator在容器上进行操作。Iterator设置算法的边界,容器的长度,和其他一些事情。举个例子,有些iterator仅让算法读元素,有一些让算法写元素,有一些则两者都行。Iterator也决定在容器中处理的方向。begin()和end()你可以通过调用容器的成员函数begin()来得到一个指向一个容器起始位置的iterator。你可以调用一个容器的end()函数来得到过去的最后一个值(就是处理停在那的那个值)。例4:vector和iterator12.5.6所有权问题(略)(课后阅读)
本文标题:类型安全的通用模板类
链接地址:https://www.777doc.com/doc-1267884 .html