预计阅读本页时间:-
const的限制
有些列表处理函数把const List *plist作为参数。这就暗示这些函数并不会修改列表。这里,const确实提供某种保护,防止*plist(plist所指向的位置的量)被修改。在这个程序里,plist指向movies,因此const防止这些函数修改movies,而只是指向列表的第一个位置。因此,例如在ListItemCount()中如下代码是不允许的:
这很不错,因为改变*plist从而改变movies,将会导致程序失去对数据的跟踪。然而,*plist和movies都被当作const,并不意味着*plist或movies指向的数据是const。例如,如下代码是允许的:
这是因为上边的代码并没有改变*plist,它只是改变了*plist所指向的数据。也就是说,你不要指望const能够捕获到意外修改数据的程序错误。
二、思考您的工作
现在花点时间来评估ADT方法给您带来了什么。首先,比较程序清单17.2和程序清单17.4。两个程序使用了同样的基本方法(动态分配的链接结构)来解决电影列表问题。但是程序清单17.2暴露了所有编程细节,将malloc()和prev->next置于公共视野中。而程序清单17.4隐藏了这些细节,并用与任务直接相关的语言来表达程序。即它讨论的是创建列表和向列表添加项目这样的任务,而不是调用内存函数或者重置指针。简而言之,程序清单17.4表达程序的方式是根据要解决的问题,而不是根据解决问题所需的低级工具。ADT版本是针对最终用户的,并且可读性更好。
其次,list.h和list.c文件共同组成可重用的资源。如果需要另一个简单列表,仍可以使用这些文件。假设您需要存储一个您亲戚的清单:姓名、关系、地址和电话号码。您需要在list.h文件中重新定义Item类型:
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
这就是在这个例子中您所要做的一切,因为所有有关简单列表的函数都是根据Item类型定义的。有时候,还需要重新定义CopyToNode()函数。比如,如果项目是一个数组,就不能通过赋值进行复制。
另一个要点是用户接口根据抽象列表操作来定义,而不是根据某些专门的数据表示和算法定义的。这使您能自由地修改实现而不用改动最后的程序。比如,当前的AddItem()函数效率不是很高,因为它总是从列表首端开始,然后去搜索尾端。您可以通过保存列表结尾处的地址来解决这个问题。比如,可以这样重新定义List类型:
当然,您得使用这个新的定义来重新编写列表处理函数,但是不需要改变程序清单17.4中的任何代码。这种把实现和最终接口相隔离的做法对于大型编程工程来说尤其有用。这称为数据隐藏,因为详细的数据表示对终端用户是不可见的。
注意这个具体的ADT甚至不要求您以链表的方法实现简单列表。下面是另一种可以使用的方法:
这也将需要重新编写list.c文件,但是使用列表的程序不需要改动。
最后,考虑这种方法为程序开发过程带来的益处。如果有些功能运行不正常,可以将问题集中到一个函数上。如果想用更好的办法来完成一个任务,比如添加项目,您只需要重写那一个函数。如果需要新的属性,您可以考虑向包中添加一个新的函数。如果您觉得使用数组或者双向链表可能更好一些,您可以重新编写实现的代码而不用修改使用实现的程序。