一、函数指针
作用在于声明函数时指定回调函数类型,函数指针是指向同返回值、参数列表的函数,与普通指针指向地址有些许区别
1. 函数指针类型
// 法一
typedef int(*Func_int_int)(int,int);
// 法二
using Func_int_int = int(*)(int,int);//容易忘记中间的*
2.函数类型
注意不存在函数变量,所以该类型无法定义变量,在特定场景下使用,作用仅在于声明函数指针或引用以及模板中传递类型参数
// 只是不要函数指针中间的*
using Func_int_int_class = int(int,int);
2. 函数指针变量
函数指针,使得函数可以保留在数组中(跳转表),也使得函数能在函数中传递并调用
- 在形参中使用如下方法声明函数指针,实参可以使用函数名直接赋值,也可以使用
&函数名
,调用时前面加不加*
都可以
// 法一
int (*funcptr)(int,int);
// 法二,使用函数指针类型,和普通变量一致
Func_int_int funcptr;
3. 成员函数指针
对于非静态成员函数,必须使用
::*
声明,取地址&::
赋值,->*
或.*
解引用调用
静态成员函数指针,和普通函数指针基本一致,只是在赋值时需要加上类的作用域&MyClass::myFunc
return_type (Class_name::*pointer_name)(parameter_types);
class MyClass {
public:
int func(int x) {
return x * 2;
}
};
// 法一
int (MyClass::*memFuncPtr)(int) = &MyClass::func;
// 法二
using MemFuncPtr = int (MyClass::*)(int);
MemFuncPtr ptr = &MyClass::func;
MyClass obj;
MyClass *pObj = &obj;
// 调用方式
(obj.*memFuncPtr)(); // 通过对象调用
(pObj->*memFuncPtr)(); // 通过指针调用
不足
- 函数指针变量必须要运行后才知道具体函数代码,无法在编译时内联
二、 函数对象
重载了operator()的类对象
1. 函数对象实例
- 创建方式
- 手动定义该类后实例化(便于理解底层原理)
- STL在
functional
中提供了大量函数类模板,如greater<T>,使用时需要将其实例化为函数对象,如greater<int>() - lambda创建
- 函数绑定器
- 函数对象与函数指针
函数指针有普通和对象函数指针,普通函数名就是函数指针(类似于数组),而对象函数名需要取地址才是函数指针(类似变量)
- 共同点:都是在后面加()后就能被调用
- 不同点:
- 两者不可交叉赋值
- 函数指针是指向代码区,要运行后才知道实际代码,所以无法内联
2. 函数对象类型
上面提过函数对象实例化后需要使用变量接受,变量又需要指定类型
- 自定义函数对象类型
std::function<函数类型>
:因为lambda创建的对象,并没有类型变量来接受,所以需要添加一个快速指定类型的方式。其本质上是函数对象类模板,内部存在函数指针指向传入的函数,实现需要使用类型推导、可变模板参数等
三、绑定器
- 底层都是函数模板,返回的是函数对象,底层依然是调用传入的函数
- 可以使用参数占位符,代表需要用户传递参数,
function<void(string)> func1 = bind(print,placeholder::_1);
- bind1st
- bind2st
- bind
// 上面代码中返回的是自定义的函数对象_mybind1st
四、lambda
- 语法:
[捕获外部变量](参数列表)->返回类型{函数体}
,如果没有返回值,可简写为[捕获外部变量](参数列表){函数体}
- 本质就是对象函数,捕获列表中变量对应构造函数中的参数,如果存在变量,则每个变量会有对应的成员数据,参数列表则对用operator()中的参数,函数体中的所有变量都会替换为对象中对应的成员数据
注意捕获列表如果是值传递,则operator()会被优化为const,函数体不能出现捕获列表参数的更改,如果要更改,可以使用
mutable
,但是并不会对捕获的变量产生任何修改
int x = 10;
auto lambda = [x](int y) { return x + y; };
//==>
class __AnonymousLambda {
const int x; // 值捕获的变量是const成员
public:
__AnonymousLambda(int x_) : x(x_) {} // 构造函数初始化捕获变量
int operator()(int y) const { return x + y; } // 默认const
};
- 无捕获lambda可以转换成函数指针,底层借助重载类型转换和静态方法实现
auto lambda = [](int a, int b) { return a + b; };
int (*funcPtr)(int, int) = lambda; // 隐式调用 operator int (*)(int, int)()
// 编译器实际生成以下内容:
// 1. 生成一个匿名类
class __Lambda_123 {
public:
int operator()(int a, int b) const {
return a + b;
}
// 关键:隐式转换为函数指针的运算符
operator int (*)(int, int)() const {
return static_cast<int (*)(int, int)>(&__Lambda_123::__invoke);
}
private:
// 2. 生成一个静态成员函数(实际执行 Lambda 体的函数)
static int __invoke(int a, int b) {
return a + b;
}
};
// 3. 实例化 Lambda 对象
__Lambda_123 lambda;