C++中的函数指针

来源:互联网 发布:kmp算法的next函数程序 编辑:程序博客网 时间:2024/05/16 09:03

  python中装饰器和偏函数两个概念。装饰器是其本质原理也是将一个函数当作参数传入另一个函数中,起到一层封装的作用,这样可以不改变原有函数的基础上而添加新的功能,比如经典的测函数运行时间,在我之前web性能测试一章用过装饰器(http://blog.csdn.net/cracker_zhou/article/details/50408514),再结合python的@语法糖就完全不用考虑实现的语法问题。python中的偏函数是将一个函数中某些位置参数固定而生成了另一个函数。
  在C++中有函数指针和指针函数两个名字相似但其实东西完全不同的概念。函数指针是一个指向函数的指针(pointer),指针函数是一个返回指针类型的函数(function)。之前我一直感叹于python中装饰器和偏函数的神奇,没想到今天竟然在C++中发现了类似的实现方式,但确实比python要多考虑语法问题。

1.最基础的传入全局函数

#include <iostream>#include <functional>typedef std::function<int(int)> func;int main(){    //等效于 int f1(int x){return x;}    func f1 = [](int x){return x; }; //lambda表达式    //等效于 void f2(func f, int y){ std::cout << f(y)<<std::endl; }    auto f2 = [](func f,int y){std::cout << f(y)<<std::endl; };//lambda表达式    f2(f1,10);  // 控制台输出10    return 0;}

  从上面代码看出,函数也是有类型的!比如这里f1的数据类型为std::function<int(int)>当我们知道函数有准确的数据类型时,我们就可以像其他int,char之类的基本数据类型传参一样理解。
  
2.传入类成员函数
  类成员函数要区分为两种:静态函数和非静态函数。
  对于类的静态函数来说其实跟上面全局函数的参数传入没什么区别,只是对于非静态函数语法上要麻烦一点,需要用bind函数绑定将函数与实例绑定。

#include <iostream>#include <functional>typedef std::function<int(int)> func;typedef std::function<int()> vfunc;class A{public:    static int add(){return 1;}    int add2(int x){ return x + 2; }};void test_add(vfunc f){ std::cout << f()<<std::endl; }void test_add2(func f, int y){ std::cout << f(y)<<std::endl; }int main(){    test_add(A::add); // 输出1    auto f2 = std::bind(&A::add2, A(), std::placeholders::_1);    test_add2(f2, 1); // 输出3    return 0;}

  从上面代码可以看出,其实对类静态函数的使用与之前的全局函数没有区别,但是当想传入非静态函数时则需要多一行bind操作,将类实例与函数绑定,额外的还需要一个参数占位符std::placeholders::_1,其实这个参数占位符也是一个很神奇的东西,下面会讲到对这个参数占位符的使用。

3.偏函数
  其实准确的说应该叫部分应用函数,大家通用的叫法是偏函数。主要通过设定参数的默认值,可以降低函数调用的难度。

#include <iostream>class A{public:    int add(int x,int y=10){ return x + y; }};int main(){    std::cout << A().add(1);   //输出11,采用了默认的y参数    return 0;}

  当使用偏函数时,可以锁定任意位置参数,其实本质上是在std::bind时提供好位置参数生成一个新的函数。

#include <iostream>#include <functional>typedef std::function<int(int)> func;class A{public:    int add(int x,int y){ return x + y*2; }};void test_add(func f, int y){ std::cout << f(y)<<std::endl; }int main(){    auto f1 = std::bind(&A::add, A(), 1,std::placeholders::_1);//锁定第一个位置参数的值为1    test_add(f1, 1); // 输出3    test_add(f1, 2); // 输出5    return 0;}

  test_add需要的第一个参数类型是std::function<int(int)>,但是在类A中add的函数是带有两个int参数的函数,其实本身这是不允许传入的。但是我们通过bind函数时锁定x位置参数使add变为带有一个int的一个新函数,名字叫f1。

4.函数指针
  如果你一定要纠结于这篇文章的标题,我就再来一个example。(其实之前一直都是值传参,只不过现在变成址传参了而已)

#include <iostream>#include <functional>typedef std::function<int(int)> func;class A{public:    int add(int x){ return x; }};void test_add(func* f,int x){ std::cout << (*f)(x)<<std::endl; }int main(){    func f1 = std::bind(&A::add, A(), std::placeholders::_1);    test_add(&f1, 1); // 输出3    return 0;}
0 0