C++理论梳理9——泛型编程的思维
泛型编程:代码与元素类型无关,与逻辑判断操作无关,与容器类型无关。通用性越强,代表代码泛化越成功。
STL概念
- standard template library(STL)主要有两部分构成:容器和操作这些容器的泛型算法。
- 之所以叫泛型算法(generic programming),是因为该算法不受限于数据类型。具体是通过fuction template技术,实现“与操作对象的类型相独立”的目的
泛型编程的典型思维过程
- 单纯处理一个存储整数的vector数据:在数据集(vector)中查找是否有给定值value,如果有就返回该值地址。可以用这样的函数
// main.cpp
int* find(const vector<int> &vec, const int value)
{
/*xxxxxxxxxxxxxxxxxxxx*/
}
- 泛化第一步:希望该函数脱离vector内元素类型的束缚:如可同时处理
vector<int>
和vector<single>
方法:模板temlpate
// main.cpp
template <typename elemType>
elemType* find(const vector<elemType> &vec, const elemType &value)
{
/*xxxxxxxxxxxxxxxxxxxx*/
}
- 泛化第二步:希望该函数脱离数据容器类型的束缚:如可同时处理vector和array。
方法:指针
// main.cpp
template <typename elemType>
elemType* find(const elemType *ptr_begin, const elemType *ptr_end, const elemType &value)
{
/*xxxxxxxxxxxxxxxxxxxx*/
}
- 泛化第三步:希望该函数进一步脱离容器类型的束缚:如可同时处理vector,array,以及list(list特殊之处在于:vector,array本质是数组,为连续存储。list本质是链表,为不连续存储。它们在指针的使用上有不通用性)。
方法:泛型指针:iterator。通常的指针可以在连续存储的数据类型(如vector和array)上进行移位操作,移动的单位距离是元素而不是位。而在非连续存储的链表里(list)可以通过链表结点的左指针和右指针找到相邻元素。但如果想要将上述两种操作统一化/泛化(使代码进一步脱离数据存储类型的束缚),就需要对list场景下的基础指针进行一些封装,即泛型指针。
// 泛型指针
// 代码解释:每个标准容器都会有一个名为begin()的操作函数,可返回一个iterator,指向第一个元素。每个标准容器还都会有一个名为end()的操作函数,可返回一个iterator,指向最后一个元素的下一个位置。
vector<string> svec;
vector<string>::iterator iter = svec.begin(); // iter被定义为一个iterator,指向一个vector,该vector的元素类型为string,iter初值指向svec的第一个元素
了解泛型指针后,则main.cpp可进一步泛化为:
// main.cpp
template <typename IteratorType, typename elemType>
IteratorType* find(IteratorType first, IteratorType last, const elemType &value)
{
for ( ; first !=last; ++first )
{
if ( value == *first )
{
return first;
}
}
return last;
}
- 泛化第四步:事实上,该main.cpp还可以更进一步泛化:把底部元素所属类型的equality相等运算符进行泛化。有两种方法,一种是函数指针,一种是function object(是一种特殊的类)。后续会补充进来。