函数指针

函数指针说白了就是一个指向函数地址的指针,因为我们对函数的调用,其实就是取函数所在的地址!函数指针定义方式为:

函数返回值类型 (指针变量名)(函数参数列表);

#include<iostream>

int SUM(int a,int b){
        return a+b;
}

//typedef int(*SumFunc)(int x, int y);	//建议这种方式,调用看起来也舒服
int(*SumFunc)(int x, int y);

int main(){
        //SumFunc sum = SUM;
        SumFunc = SUM;
        //int ret = sum(1,2);
        int ret = (*SumFunc)(1,2);	//为什么要用*,因为取地址 解引用
        std::cout<< ret<<std::endl;
}

函数对象

函数对象,也就是 Function Object, 也被称为 Functor,它可以被当作一个函数来调用。通常指重载了 operator() 的类对象。

class FuncObjType
{
public:
    void operator() (std::string str)
    {
        cout<<"Hello "<<str<<endl;
    }
};

int main(){
    FuncObjType obj;	//函数对象
    obj("C++");			//就会输出Hello C++!
}

该调用语句在形式上跟以下函数的调用完全一样:

void val()
{
    cout<<"Hello C++!"<<endl;
}

既然用函数对象调用普通函数有相同的效果,为什么还有搞这么麻烦定义一个类来使用函数对象?

主要在于函数对象有以下的优势:

  • 可以定义成员变量(作为自己的状态),这样函数对象多次调用时可以使用这个状态。普通函数除非使用全局变量
  • 函数对象有类型

Lambda

最重要的作用就是可以创建匿名函数对象,就无需写一个普普通通的函数类,然后又重载一个括号运算符。

#include<vector>
#include<vector>
#include<iostream>
#include<algorithm>

int main()
{
    int count = 0;
    std::vector<std::string> words{ "An", "ancient", "pond" };
    
    std::for_each(words.cbegin(), words.cend(),
                 [&count](const std::string& word)
                  {
                      if(isupper(word[0])) {
                          std::cout << word << " " << count << std::endl;
                          count++;
                      }
                  });
}

这样的代码在编译时,lambda表达式会自动转变成一个类——它每一个成员变量都对应着一个捕获的变量。这个类根据lambda表达式的参数列表重载了operator(),一个可能的实现如下:

class lambda_implementation {
public:
    lambda_implementation(int& n) : count_(n) {}
    
    void operator()(const std::string& word) const
    {
        if(isupper(word[0]))
        {
            std::cout << word << " " << count << std::endl;
            count_++;
        }
    }
private:
    int& count_;
}

std::function

std::function 是一个函数包装器模板,一个 std::function 类型对象可以包装以下类型:

  • 函数指针
  • 类成员函数指针 (如使用 std::bind 传递)
  • 函数对象(定义了 operator() 操作符的类对象)
//声明一个模板  
typedef std::function<int(int)> Functional;  
  
//normal function  
int TestFunc(int a)  
{  
    return a;  
}  
  
//lambda expression  
auto lambda = [](int a)->int{return a;};  
  
//functor仿函数  
class Functor  
{  
public:  
    int operator() (int a)  //必须重载()
    {  
        return a;  
    }  
};  
  
  
//类的成员函数和类的静态成员函数  
class CTest  
{  
public:  
    int Func(int a)  
    {  
        return a;  
    }  
    static int SFunc(int a)  
    {  
        return a;  
    }  
};  
  
  
int main(int argc, char* argv[])  
{  
    Functional obj = TestFunc; 

    //封装普通函数  
    int res = obj(0);  
    cout << "normal function : " << res << endl;  
  
    //封装lambda表达式  
    obj = lambda;  
    res = obj(1);  
    cout << "lambda expression : " << res << endl;  
  
    //封装仿函数  
    Functor functorObj;  
    obj = functorObj;  
    res = obj(2);  
    cout << "functor : " << res << endl;  
  
    //封装类的成员函数
    CTest t;  
    obj = std::bind(&CTest::Func, &t, std::placeholders::_1);  
    res = obj(3);  
    cout << "member function : " << res << endl;  
  	
    //类的static方法
    obj = CTest::SFunc;  
    res = obj(4);  
    cout << "static member function : " << res << endl;  
  
    return 0;  
}  

std::bind就是可以创造闭包的工具,一般配合std::function使用。(闭包:在函数式编程中,通过组合现有的函数,可以创造出新的函数。)

#include<algorithm>

class Foo
{
 public:
  void methodA();
  void methodInt(int a);
};
class Bar
{
 public:
  void methodB();
};

void main()
{
    std::function<void()> f1; // 无参数,无返回值

    Foo foo;
    f1 = std::bind(&Foo::methodA, &foo);
    f1(); // 调用 foo.methodA();
    Bar bar;
    f1 = std::bind(&Bar::methodB, &bar);
    f1(); // 调用 bar.methodB();

    f1 = std::bind(&Foo::methodInt, &foo, 42);
    f1(); // 调用 foo.methodInt(42),只是入参给写死了,有些场景可能需要

    std::function<void(int)> f2; // int 参数,无返回值
    f2 = std::bind(&Foo::methodInt, &foo, _1);
    f2(53); // 调用 foo.methodInt(53);
}