编程范式|程序世界里的编程范式,探索编程本质 (2)

然后,我们对数据容器的遍历使用了Iter中的++方法,这是数据容器需要重载的操作符,这样通过操作符重载也就泛型掉了遍历,
为了兼容原有 C 语言的编程习惯我们不用标准接口Iter.Next(),不用Iter.GetValue()来取代*。

在函数的入参上使用了pStart和pEnd来表示遍历的起止。

使用Iter来取得这个“指针”的内容。这也是通过重载 取值操作符来达到的泛型。

说明:所谓的Iter,在实际代码中,就是像vector::iterator或map<int, string>::iterator这样的东西。这是由相应的数据容器来实现和提供的(迭代器)。

C++ STL源码中的find函数

template<class InputIterator, class T> InputIterator find (InputIterator first, InputIterator last, const T& val) { while (first!=last) { if (*first==val) return first; ++first; } return last; } C++的范式例子2: Sum 函数

C语言版求和函数

long sum(int *a, size_t size) { long result = 0; for(int i=0; i<size; i++) { result += a[i]; } return result; }

C++泛型版(有问题):

template<typename T, typename Iter> T sum(Iter pStart, Iter pEnd) { T result = 0; for(Iter p=pStart; p!=pEnd; p++) { result += *p; } return result; }

这里默认了 T result = 0;也就是T假设了 Iter 中出来的类型是T。0假设了类型是int;如果类型不一样,就会导致转型的问题

改进版,需要迭代器
Iter在实际调用者那会是一个具体的像vector::iterator的东西
在这个声明中,int已经被传入Iter中了;所以定义result的T应该可以从Iter中来。这样就可以保证类型是一样的,而且不会有被转型的问题。

C++ 泛型编程:迭代器 template <class T> class container { public: class iterator { public: typedef iterator self_type; typedef T value_type; typedef T* pointer; typedef T& reference; reference operator*(); pointer operator->(); bool operator==(const self_type& rhs); bool operator!=(const self_type& rhs); self_type operator++() { self_type i = *this; ptr_++; return i; } self_type operator++(int junk) { ptr_++; return *this; } ... ... private: pointer _ptr; }; iterator begin(); iterator end(); ... ... };

1.首先,一个迭代器需要和一个"数据容器"(类)在一起,因为里面是对这个容器的具体的代码实现,对这个容器的迭代。
2.它需要重载一些操作符,比如:取值操作*、成员操作->、比较操作==和!=,还有遍历操作++,等等。
3.然后,还要typedef一些类型,比如value_type,告诉我们容器内的数据的实际类型是什么样子。
4.还有一些,如begin()和end()的基本操作。
5.我们还可以看到其中有一个pointer _ptr的内部指针来指向当前的数据(注意,pointer就是 T*)。

有了迭代器,我们让用户自型传入模板T的类型,解决T result = 0出现的问题
最终Sum的范式写法:

template <class Iter> typename Iter::value_type sum(Iter start, Iter end, T init) { typename Iter::value_type result = init; while (start != end) { result = result + *start; start++; } return result; } int main(){ container<int> c; container<int>::iterator it = c.begin(); sum(c.begin(), c.end(), 0); return 0; }

这就是整个 STL 的泛型方法,其中包括:

1.泛型的数据容器;
2.泛型数据容器的迭代器;
3.泛型的算法;

reduce函数式编程

如果我们有一个 员工结构体,再想用sum函数来求和怎么办?

struct Employee { string name; string id; int vacation; double salary; };

结构体数组增加了很多数据类型,以前sum函数就不知道怎么办了吧,

vector<Employee> staff; //total salary or total vacation days? sum(staff.begin(), staff.end(), 0);

这个例子而言,我想计算员工薪水里面最高的,和休假最少的,或者我想计算全部员工的总共休假多少天。那么面对这么多的需求,我们是否可以泛型一些呢?怎样解决这些问题呢?
引入更抽象化的函数编程——reduce函数

template<class Iter, class T, class Op> T reduce (Iter start, Iter end, T init, Op op) { T result = init; while ( start != end ) { result = op( result, *start ); //这里时重点 start++; } return result; }

reduce函数 需要增加一个参数 op,这个参数可以是一个函数,来完成我们想要的业务操作。

比如下面的业务操作函数:我们来求员工的工资和、最大工资

double sum_salaries = reduce( staff.begin(), staff.end(), 0.0, {return s + e.salary;} ); double max_salary = reduce( staff.begin(), staff.end(), 0.0, {return s > e.salary? s: e.salary; } ); C++STL中的count_if():

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywsyw.html