泛型编程
泛型编程
泛型编程-概观
- 泛型编程(Generic programming) 是一种编程方法,这种方法将类型(type)以一种to-be-specified-later的方式给出,等到需要调用的时候,再以参数方式,通过具体的、特定的类别实例化(instantiate)一个具体的方法或对象
- 泛型编程作为一种编程的想法或思想,不依赖具体的语言
- 大多数面向对象的语言(O O languages)都支持泛型编程,(只不过在C++种以模板的这种形式表现出来)比如:C++、C#、Java、Ada….
- C++里面的泛型是通过模板以及相关性质表现出来
特性(Traits)
- 什么是traits以及为什么使用traits?
假设给定一个数组,计算数组种所有元素的和:
A[0] | A[1] |…| A[n] $\sum_{k=0}^n A[k]$
我们可以很直接地写出如下的计算函数:
template <typename T> inline T Sigma(const T const* start, const T const* end) { T total = T(); // suppose T() actually creates a zero value //T()是一个构造函数目的将total初始化为0; while (start != end) { total += *start ++ ; } return total; }
当我们使用char类型调用模板函数是,问题就来了:
char szNames[] = "abc"; std :: size_t nLength = strlen(szNames); char* p = szNames; char* q = szNames + nLength; printf("sigma(ezNames) = %d\n", Sigma(p,q));
Char类型能hold住的最大值为0xFF = 255 也就是两个字节所以0010和0110可容纳的但是abc加起来大于255就溢出到溢出到1这个bit
调用Sigma(szNames)的结果是38( = 0x26)!而并不是所期望的值(97 + 98 + 99 = 294)
- 原因显而易见的:char无法存下这个294这个值
- 如果要得到正确的结果,我们就不得不强制使用int类型:
int s = Sigma<int>(p,q);
- 但是这种不必要的转换是完全可以避免的!
- 解决方法是:为每个Sigma函数的参数类型T创建一种关联(association),关联的类别就是用来储存Sigma结果的类型
- 这种关联可以看作是类型T的一种特性(characteristic fo the type T),因为sigma函数返回值的类型叫做T的trait
- T与其trait的关系推演如下:
T -> association -> characteristic of T -> another type -> trait - Traits可以实现为模板类,而关联(association)则是针对每个具体类型T的特化。在这个例子里我们将trait命名为SigmaTraits, 叫做traits模板(traits template)
Traits实现:
template <typename T>
class SigmaTraits { };
//可以人为的将返回的数值边得相对的大
template <>
class SigmaTraits<char> {
public:
typedef int ReturnType;
};
template <>
class SigmaTraits<short> {
public:
typedef int ReturnType;
};
template <>
class SigmaTraits<int> {
public:
typedef long ReturnType;
};
template <>
class SigmaTraits<unsigned int> {
public:
typedef unsigned long ReturnType;
};
template <>
class SigmaTraits<float> {
public:
typedef double ReturnType;
};
- 模板类SigmaTraits叫做traits template, 它含有其参数类型T的一个特性(trait), 即ReturnType
现在Sigma函数可以改写成:
template <typename T> inline typename SigmaTraits<T> :: ReturnType Sigma (const T const* start, const T const* end) { typedef typename SigmaTraits<T> :: ReturnType ReturnType; ReturnType s = ReturnType(); while (start != end) { s += *start ++; } return s; }
迭代器(iterator)
什么是迭代器?
迭代器是指针的泛化(generalization of pointers)
- 迭代器本身就是一个对象,指向另外一个(可以被迭代的)对象
- 用来迭代一组对象,即如果迭代器指向一组对象种的某个元素,则通过increment以后它就可以指向下组对象中的下一个元素
在STL中迭代器是容器与算法之前的接口
- 算法通常以迭代器作为输入参数
- 容器只要提供一种方式,可以让迭代器访问容器中的元素即可
迭代器的基本思想
- 在STL中,迭代器最终要的思想就是分离算法和容器,使之不需要相互依赖
迭代器将算法和容器粘合(stick)在一起从而使得一种算法的实现可以运用到多种不同的容器上,如下面的例子,find算法接受一对迭代器,分别指向容器的开始位置和最终位置
template <typename _InIt, typename _Ty> inline _InIt find(_InIt _First, _InIt _Last, const _Ty& _Val) { //find first matching _Val for (; _First != _Last; ++_First) { if (*_First == _Val) break; } return (_First); }
find算法对于不同的容器,比如vector, list, deque均适用:
std :: vector<int> v(...); std :: list<int> l(...); std :: deque<int> d(...); std :: vector<int> :: iterator itv = std :: find(v.begin(), v.end(), elementToFind) std :: list<int> :: iterator itl = std :: find(l.begin(), l.end(), elementToFind) std :: deque<int> :: iterator it3 = std :: find(d.begin(), d.end(), elementToFind)
每种容器都有其对应的迭代器
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!