1、可调用对象
可调用对象是C++11引入的概念,可以像函数调用方式的触发调用的对象就是可调用对象。如下是可调用对象的几种定义:
1.1、函数指针
函数指针的可调用对象的测试代码:
#include<iostream>
#include<string>
int myTest(int a, std::string b)
{
std::cout << "a = " << a << " b = " << b << std::endl;
return 0;
}
//定义函数指针---->C++98
typedef int(*func)(int, std::string);
//使用using定义函数指针--->C++11
using func1 = int(*)(int, std::string);
int main()
{
func f= myTest;
func1 f1 = myTest;
f(10, "Naruto");
f1(20, "Sakura");
return 0;
}
测试代码的结果:
1.2、仿函数对象
仿函数的意思就是类似于函数的意义,一般是指写入了operator()运算符方法的类就是一个仿函数,如下是一个具有operator()成员函数的类对象:
#include<iostream>
#include<string>
class Test
{
public:
Test() = default;
void operator()(std::string msg)
{
std::cout << "msg:" << msg << std::endl;
}
};
int main()
{
Test t;
t("I want to be Naruto");
return 0;
}
测试代码的结果:
1.3、类对象转化为函数指针
可调用对象的最后一个常见的类型为类对象转化为函数指针,测试代码如下:
#include<iostream>
#include<string>
//使用using定义函数指针
using funcPtr = void(*)(int, std::string);
class Test
{
public:
Test() = default;
static void printMsg(int a, std::string b)
{
std::cout << "I am " << b << " is " << a << " years old";
}
//类对象转化为函数指针
operator funcPtr()
{
return printMsg;
}
};
int main()
{
Test t;
t(20, "Naruto");
return 0;
}
测试代码的结果:
注意:上面例举的都是常用的可调用对象,不是只有3种可调用对象!!!
2、可调用对象的包装器
std::function是可调用对象的包装器。它是一个类模板,可以容纳除了类成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟执行它们。
2.1、std::function的使用方法
在使用std::function之前首先要包含它的头文件functional,它的语法如下:
//导入头文件
#include <functional>
//包装器的语法
std::function<返回值类型(参数类型列表)> diy_name = 可调用对象;
下面简单演示可调用对象的包装器的使用:
#include<iostream>
#include<functional>
#include<string>
void printMsg(int age, std::string name)
{
std::cout << "I am " << name << " is " << age << " years old" << std::endl;
}
class Test1
{
public:
Test1() = default;
static int add(int a, int b)
{
std::cout << "a + b = " << a + b << std::endl;
return a + b;
}
};
class Test2
{
public:
Test2() = default;
int operator ()(int a, int b)
{
std::cout << "a * b =" << a * b << std::endl;
return a * b;
}
};
int main()
{
//包装普通函数
std::function<void(int, std::string)>f1 = printMsg;
//包装类中的静态函数
std::function<int(int, int)>f2 = Test1::add;
//包装仿函数
Test2 t2;
std::function<int(int, int)>f3 = t2;
//函数的调用
f1(20, "Naruto");
f2(2, 2);
f3(5, 5);
return 0;
}
测试代码的结果:
通过上面的代码可知,std::function可以对可调用对象进行包装,得到一个统一的格式,包装完成后得到的包装器对象相当于一个仿函数,向里面传入参数即可完成函数调用。
2.2、作为回调函数
因为回调函数本身是通过函数指针实现,在C++11以后我们可以通过可调用对象的包装器取代函数指针,实现回调函数,测试代码如下:
#include<iostream>
#include<functional>
#include<string>
class Test1
{
public:
//初始化包装器
Test1(const std::function<void()>& f) : m_callBack(f)
{
}
void doSomething()
{
m_callBack();
}
private:
std::function<void()>m_callBack;
};
class Test2
{
public:
Test2() = default;
void operator()()
{
std::cout << "hello World" << std::endl;
}
};
int main()
{
//通过构造函数获取包装器,执行回调函数
Test2 t2;
Test1 t1(t2);
t1.doSomething();
return 0;
}
测试代码的结果: