C++手稿:STL中的函数对象与函数指针

来源:互联网 发布:淘宝开网店哪里进货 编辑:程序博客网 时间:2024/05/16 05:37

先来感受一下C++中的函数对象和函数指针:

template<typename T>void printer(int a, int b, T func){    cout<<func(a, b)<<endl;}

在STL中定义了很多像上面这样的模板,这里的T是一个可调用(实现了括号运算符)的东西。 这使得我们在使用模板时可以指定一个计算策略,它可以是函数对象,也可以是函数指针。

Less<int>便是一个常见的函数对象,常用来配置容器或算法。<functional>中定义了很多这样的函数对象。

函数指针

函数指针通常用来将函数传参或存储。例如:

int sum(int a, int b){    return a+b;}int main(){    printer(2, 3, sum);    return 0;}

上述的printer调用方式,编译器会生成对应的函数实例:

void printer(int a, int b, int (*func)(int, int)){    cout<<func(a, b)<<endl;}

这里T的类型是int (*)(int, int)

如果你是python或者javascript程序员的话,上述过程没有什么特别的。 唯一要注意的是func的声明方式,星号要和标识符括起来:(*func)

函数对象

函数对象是重载了括号运算符的类的实例,它也可以这样调用:func(a, b)。例如:

class Sum{public:    int operator()(int a, int b){        return a+b;    }};int main(){    printer(2, 3, Sum());    return 0;}

编译器会生成这样的函数实例:

void printer(int a, int b, Sum s){    cout<<s(a, b)<<endl;}

函数对象可以实现更加复杂的有状态的运算,因为对象可以有更多的属性和方法。

std::accumulate

#include <iostream>     // std::cout#include <functional>   // std::minus#include <numeric>      // std::accumulateint myfunction (int x, int y) {return x+2*y;}struct myclass {      int operator()(int x, int y) {return x+3*y;}} myobject;int main () {    int init = 100;    int numbers[] = {10,20,30};    std::cout << std::accumulate(numbers,numbers+3,init) << std::endl;    std::cout << std::accumulate (numbers, numbers+3, init, std::minus<int>()) << std::endl;    std::cout << std::accumulate (numbers, numbers+3, init, myfunction) << std::endl;    std::cout << std::accumulate (numbers, numbers+3, init, myobject) << std::endl;    return 0;}

在这里accumulate的第四个参数默认值为std::plus<int>(),是一个函数对象, std::minus<int>()也是一个函数对象,它们都是在functional中定义的。 myfunction是函数指针,而myobject是自定义的函数对象。输出如下:

16040220280

摘自cplusplus.com: http://www.cplusplus.com/reference/numeric/accumulate

比较器:std::sort

需要比较元素大小的STL算法、容器的模板、容器的成员函数,都可以给定一个比较策略。它们的默认值通常是Less<T>()

例如,指定greater函数对象作为比较器,就可以实现反向排序:

sort(v.begin(), v.end(), greater<int>());

std::sort要求随机存取迭代器,list不可用std::sort,可以使用list::sort(Pred pr)

std::sort实际上是快排,复杂度为O(nlgn),它是不稳定的。stale_sort则是稳定的归并排序。

比较器:模板参数

关联容器通常使用搜索树来实现,所以插入元素时需要进行比较操作。 我们在使用容器模板时可以指定比较器:

class A{    int n;public:    A(int _n):n(_n){}    bool operator<(const A& lhs, const A& rhs){        return lhs.n < rhs.n;    }};multiset<A, less<A>> s;s.insert(A());

默认情况下关联容器使用less模板来进行元素比较,而less中调用了<, 所以默认情况下插入关联容器的元素需要实现<运算符:

如果未实现相应的比较运算符,insert操作会编译错。因为运算符调用本质上是函数调用。

0 0
原创粉丝点击