半小时掌握C++之function类模板

124 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情

函数调用运算符

  • ()圆括号是函数调用的明显标记, ()也叫函数调用运算符;
  • 如果在类中重载了函数调用运算符,就可以想使用函数一样使用该类的对象了;
  • 只要对象所属的类重载了 ()函数调用运算符,那么这个类对象就变成了可调用的;

函数对象

1、调用类的成员函数,函数名为operator()(参数)

写法apple.operator()(参数);

可以简写为apple(参数)

此时apple(参数)这个使用方法,和一个真正的函数调用的写法是一样的,比如fun(参数)

所以称呼apple为一个函数对象,类A就是一个函数对象类

#include <iostream>
using namespace std;
class A{
public:
    int i = 8;
    void operator()(int value){
        cout<<"类的operator()函数被调用"<<endl;
        cout<<"value+100="<<value+100<<endl;
    }
};
void fun(int value){
    cout<<"fun函数被调用"<<endl;
    cout<<"value+100="<<value+100<<endl;
}
int main(){
    A apple;
    apple(9);
    fun(9);
    apple.operator()(9);
    return 0;
}
/*
类的operator()函数被调用
value+100=109
fun函数被调用
value+100=109
类的operator()函数被调用
value+100=109
*/

和有参构造的区别

如果前面有类名,说明要调用有参构造

如果前面没有类名,说明要调用重载小括号函数

#include <iostream>
using namespace std;
class A{
public:
    int i = 8;
    void operator()(int value){
        cout<<"类的operator()函数被调用"<<endl;
        cout<<"value+100="<<value+100<<endl;
    }
    A(int value){
        cout<<"类的有参构造被调用"<<endl;
        i = value;
    }
};
void fun(int value){
    cout<<"fun函数被调用"<<endl;
    cout<<"value+100="<<value+100<<endl;
}
int main(){
    A apple(55);
    apple(1);
    fun(2);
    apple.operator()(3);
    return 0;
}
/*
类的有参构造被调用
类的operator()函数被调用
value+100=101
fun函数被调用
value+100=102
类的operator()函数被调用
value+100=103
*/

小结

如果这个对象所属的类重载了"()",那么这个类对象就变成了可调用对象(函数对象),而且可以调用多个版本的"()",只要在参数类型或者数量上有差别就行。

函数类型

函数类型就是函数的返回值和参数类型的组合

int(int)
int(double)

用函数指针来调用可调用对象

可调用对象有:函数,函数指针,lambda表达式,bind创建的对象,以及重载了函数调用符的类。

int (*p1) (int value);
p1 = A::operator();
p1 = operator();
A a;
p1 = a.operator();//以上都不行
​
void fun(int value){
    cout<<"fun函数被调用"<<endl;
    cout<<"value+100="<<value+100<<endl;
}
void (*p1) (int value);
p1 = fun;//可以
p1(100);

都会报错,指向绑定函数的指针只能用于调用函数,不能用于调用函数对象

解决方法,function类模板

function类模板

function是一个通用的多态函数包装器。 std :: function的实例可以存储,复制和调用任何可调用的目标 :包括函数,lambda表达式,绑定表达式或其他函数对象,以及指向成员函数和指向数据成员的指针

需要头文件#include

#include <iostream>
#include <functional>
using namespace std;
class A{
public:
    int i = 8;
    void operator()(int value){
        cout<<"类的operator()函数被调用"<<endl;
        cout<<"value+100="<<value+100<<endl;
    }
};
void fun(int value){
    cout<<"fun函数被调用"<<endl;
    cout<<"value+100="<<value+100<<endl;
}
int main(){
    function<void(int)> func1 = A();
    A apple;
    function<void(int)> func2 = apple;
    function<void(int)> func3 = fun;
    func1(100);
    func2(200);
    func3(300);
    
    return 0;
}
/*
类的operator()函数被调用
value+100=200
类的operator()函数被调用
value+100=300
fun函数被调用
value+100=400
*/

通过map调用

#include <iostream>
#include <functional>
#include <map>
using namespace std;
class A{
public:
    int i = 8;
    void operator()(int value){
        cout<<"类的operator()函数被调用"<<endl;
        cout<<"value+100="<<value+100<<endl;
    }
};
void fun(int value){
    cout<<"fun函数被调用"<<endl;
    cout<<"value+100="<<value+100<<endl;
}
int main(){
    function<void(int)> func1 = A();
    A apple;
    function<void(int)> func2 = apple;
    function<void(int)> func3 = fun;
    map<string,function<void(int)>> mymap;
    mymap.insert({"callbyA",func1});
    mymap.insert({"callbyApple",func2});
    mymap.insert({"callbyfunc",func3});
    cout<<"---通过容器mymap调用---"<<endl;
    mymap["callbyA"](7);
    mymap["callbyApple"](8);
    mymap["callbyfunc"](9);
    return 0;
}
/*
---通过容器mymap调用---
类的operator()函数被调用
value+100=107
类的operator()函数被调用
value+100=108
fun函数被调用
value+100=109
*/

typedef定义函数指针类型的写法

#include <iostream>
#include <functional>
#include <map>
using namespace std;
class A{
public:
    int i = 8;
    void operator()(int value){
        cout<<"类的operator()函数被调用"<<endl;
        cout<<"value+100="<<value+100<<endl;
    }
};
void fun(int value){
    cout<<"fun函数被调用"<<endl;
    cout<<"value+100="<<value+100<<endl;
}
int main(){
    map<string,void (*) (int)> v1;
    void (*p3) (int);
    p3 = fun;
    v1.insert({"func1",p3});
    v1["func1"](55);
    cout<<"----typedef----"<<endl;
    typedef void (*Func) (int);
    Func p4 = fun;
    map<string,Func> v2;
    v2.insert({"func1",p4});
    v2["func1"](55);
    return 0;
}
/*
fun函数被调用
value+100=155
----typedef----
fun函数被调用
value+100=155
*/

由此可见当要创建多个函数指针的时候,建议用typedef。

值得注意的是

map<string,void (*) (int)> v1;

括号中*没带参数,和string不带参数一样的道理