前段时间读了一本书《C++沉思录》,偶有感,摘录如下:
模板和泛型算法(摘自 《c++沉思录》):
一个特例:
1.假设我们希望从整数数组中找到第一个等于某给定值的元素.编写如下代码:
const int*
find1(const int* array, int n, int x)
{
const int *p = array;
for( int i = 0; i < n; i++)
{
if(*p==x)
return p;
++p;
}
return 0;
}
2.泛型化元素类型:
用类型T来表示整型等,适当的时候可以把const也包含在T中,得到如下函数.
template<class T>
T* find2(T* array, int n, constT& x)
{
T* p = array;
for(int i=0; i<n; i++)
{
if(*p==x)
return p;
++p;
}
return 0;
}
3.推迟计数.
为了避免预先知道有多少个元素,我们改变函数,使它接受指向第一个元素和最后一个元素之后元素的指针.
template<class T>
T* find3(T* array, T* beyond, constT& x)
{
T* p = array;
while(p!=beyond)
{
if(*p ==x)
return x;
++p;
}
return 0;
}
用!=而不用<来判断循环结束并不是偶然.从某种角度来说,两者没有区别,如果find3的输入有意义,则p就小于beyond,直到它们相等为止.但是,由<加以总体排序的类型通常也能用!=来进行比较.另一方面,考虑一下我们以后可能会用到来代替指针的类型,他们可以很好地定义!=,但不一定能定义<.此时,使用<就是一个不合理的假设.
另外,我们还假设了,0可以转换成一个与其他所有的值不同的指针值.我们稍微做一点改变,以避免这种假设:如果程序中要找的值没找到,它就返回beyond而不是0.
template<class T>
T* find4(T* array, T* beyond, constT& x)
{
T* p = array;
while(p!=beyond)
{
if(*p ==x)
return x;
++p;
}
return beyond;
}
因为程序要么返回适当的T*, 要么返回beyond.故程序代码可以被修改如下:
template<class T>
T* find5(T* array, T* beyond, constT& x)
{
T* p = array;
while(p!=beyond && *p != x)
++p;
return p;
}
4.地址的独立性
到目前为止,我们还是依赖于传递来的指针,该指针要指向要查找的数据的开头.但是如果仔细分析一下,会发现我们只依赖于指针的某些保留特性:
1)可以把指针当参数接收,并把它们作为结果返回.
2)可以比较指针是否相等.
3)可以解除引用,以便得到值:*p.
4)可以递增,以指向下一个元素.
只要符合上述条件的类型即可,不一定是指针类型.假设把T*作为模板参数,我们就取消了对指针的依赖:
template<class P,class T>
T* find6(P start, p beyond, constT& x)
{
while(start !=beyond && *start != x)
++start;
return start;
}
我们已经完全剔除了函数中关于具体类型的信息.根本没有要求p是指针,只要求p满足上述的四个特性.