下面直接跳过第二部分的两个例子,随后我会分析的,直接进入模板这一章。
1首先说下容器该包含什么?
C1.insert(obj),假如我们把obj放入C1中,当我们操作obj的时候是否会影响到C1,这里也就牵扯到两类:一种是指针,一种是值。
2当我们赋值的时候,一般采取值复制。
3另外获取容器的值,是得到类型T还是类型T&的对象?
4关于容器的读和写,当用[]进行读的时候,我们可能会遇到容器中套容器的尴尬,Container<Container<int>> C;这样出现C[i][j],我们就傻眼了。当然我们可以用一个函数来获得。但参数的索引数目可能会随着嵌套越来越多,我们也可以用C[i].update(j,new_value),(update(int index,const T&t),可惜[]操作符返回的必须是引用才可以这样用,不然你改的是复制的类。
5怎么处理容器的增长?
事先分配的内存大于实际存储的内存。
6容器一般不应该存在继承关系。
定义MyArray类,并对它进行访问,这里我们用到了三个类,一个类MyArray_data,一个是Pointer,以及MyArray本身,后两者都指向MyArray_data,MyArray_data中维护一个指针用来说明几个类在引用它。当然还有const类型数据,只用将Pointer继承自Ptr_to_const这个新类就行了。
其实Pointer就是一个迭代器。
作者还提出了如何删除容器中的元素,以及删除容器(将删除容器的操作延后到最后一个迭代器,这只是一种方法),作者提供了许多种思想,各有利弊。
这章的内容还是不太理解,以后还会回头慢慢体会的。
序列部分说白了,就是一个用链表实现的不支持删除,修改数据的,用引用计数实现的Lisp,支持5种基本概念,
l Nil:没有元素的列表
l Cons(a,b):在列表中,第一个元素为a,其后的元素为列表b的元素。
l Car(s):s的第一个元素,而s必须是至少有一个元素的列表。
l Cdr(s):s的第一个元素之外的其他所有元素,其中s是至少有一个元素的列表。
l Null(s):如果s没有元素则为真,反之为假,s必须是个列表。
当然可以加入需要的操作。
作为接口的模板(重点关注的)
作者提到了一个求和算法,一个整形数组进行求和,int sum(int* p, int n);作者用迭代器替代了指针p,然后对迭代器进行泛型化,sum只需传入一个迭代器即可进行操作。随后要做的工作就是把sum改造为模板函数,参数为模板迭代器,此时的迭代器可以通过继承多态方式传递参数(会增加开销,因为用到虚函数),不采取继承,通过template<class T,class Iter> void sum2(T& result,Iter ir){result = 0; while(ir.valid()) result += ir.next()}来实现,单纯的template<class Iter,class T> T sum(Iter ir)这样是非法的,因为返回值是与参数类型无关的参数。可以对sum进行重载 template<class T> T sum(T* p,int n){T r = 0; sum2(r,Iterator<T>(p,n));return r;}客户端就不必关注底层了,解决的问题就是以下三个的抽象:
l 把一组数加起来
l 加的数是整数
l 加完后以一种特殊方式存储起来
(其实还是不太懂,哎。。。)