如何定义一个函数指针
-
什么是函数指针 ? 如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫做函数指针变量,简称函数指针。 -
指针变量如何定义呢 ? 虽然同样是指向一个地址,但是指向函数的指针变量同我们之前的指向变量的指针变量的定义方式是不同的。例如: int (*p)(int ,int)
这个语句就定义了一个指向函数的指针变量 p ,首先它是一个指针变量,所以要有一个 “*” ,即 (*p) ; 其次前面的这个 int 表示这个指针变量可以指向返回值类型为 int 的函数 ; 后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型 的函数。所以合起来这个语句的意思就是:定义了一个指针变量 p ,该指针变量可以指向返回类型为 int ,且有两个整型参数的函数。p 的类型为 int (*)(int, int) 。 所以函数指针的定义方式为: 函数返回值类型 (*指针变量名) (函数参数列表)
“函数返回值类型” 表示该指针变量可以指向具有什么返回值类型的函数;“函数参数列表” 表示该指针变量可以具有什么参数列表的函数。这个参数列表中只需要写函数的参数类型即可。 我们看到,函数指针的定义就是将“函数声明”中的“函数名”改成“(*指针变量名)”。但是这里需要注意的是:“(*指针变量名)”两端的括号不能省略,括号改变了运算符的优先级。如果省略了括号,就不是定义函数指针而是一个函数声明了,即声明了一个返回值类型为指针型的函数。 那么怎么判断一个指针变量是指向变量的指针变量还是指向函数的指针变量呢?首先看变量名前面有没有“”,如果有“”说明是指针变量;其次看变量名的后面有没有带有形参类型的圆括号,如果有就是指向函数的指针变量,即函数指针,如果没有就是指向变量的指针变量。 -
如何利用函数指针调用函数 ? int Func(int x);
int (*p) (int x);
p = Func;
赋值时函数 Func 不带括号,也不带参数。由于函数名 Func 代表函数的首地址,因此经过赋值以后,指针变量 p 就指向函数 Func() 代码的首地址了。
std::function 的用法 ?
类模板 std::function 是一种通用、多态的函数封装。std::function 的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda 表达式、函数指针、以及其它函数对象等。std::function 对象是对 C++中现有的可调用实体的一种类型安全的包裹(我们只掉像函数指针这类可调用实体,是类型不安全的)。
通常 std::function 是一个函数对象类,它包装其它任意的函数对象,被包装的函数对象具有类型为 T1,TN 的 N 个参数,并且返回一个可以转换到 R 类型的值。std::function 使用模板转换构造函数接收被包装的函数对象;特别是,闭包类型可以隐式地转换为 std::function 。
通过 std::function 对 C++ 中各种可调用实体(普通函数、Lambda表达式、函数指针、以及其它函数对象等)的封装,形成一个新的可调用的 std::function 对象;让我们不再纠结那么多的可调用实体。一切变得简单粗暴。
关于可调用的实体转换成 std::function 类型的对象,的注意事项:
- 关于可调用实体转换为 std::function 对象需要需要遵守以下两条原则
- 转换后的 std::function 对象的参数能转换为可调用实体的参数
- 可调用实体的返回值能转换为 std::function 对象的返回值
- std::function 对象最大的用处就是在实现函数回调,使用者需要注意,他不能被用来检查相等或者不相等,但是可以与NULL或者nullptr进行比较。
#include<iostream>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<string>
#include<algorithm>
#include<functional>
#include<memory>
using namespace std;
typedef std::function<int(int)> Functional;
int TestFunc(int a)
{
return a;
}
auto lambda = [](int a)->int {return a; };
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;
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;
obj = CTest::SFunc;
res = obj(4);
cout << "static member function : " << res << endl;
return 0;
}
std::bind 介绍
std::bind 函数将可调用对象和可调用对象的参数进行绑定,返回新的可调用对象(std::function 类型,参数列表可能改变),返回的新的std::function可调用对象的参数列表根据bind函数实参中std::placeholders::_x从小到大对应的参数确定
参考下面代码:
#include<iostream>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<string>
#include<algorithm>
#include<functional>
#include<memory>
using namespace std;
class A
{
public:
void fun_3(int k, int m)
{
cout << k << " " << m << endl;
}
};
void fun(int x, int y, int z)
{
cout << x << " " << y << " " << z << endl;
}
void fun_2(int& a, int& b)
{
a++;
b++;
cout << a << " " << b << endl;
}
int main(int argc , char ** argv)
{
auto f1 = std::bind(fun, 1, 2, 3);
f1();
auto f2 = std::bind(fun, placeholders::_1, placeholders::_2, 3);
f2(1, 2);
auto f3 = std::bind(fun, placeholders::_2, placeholders::_1, 3);
f3(1, 2);
int n = 2, m = 3;
auto f4 = std::bind(fun_2, n, placeholders::_1);
f4(m);
cout << m << endl;
cout << n << endl;
A a;
auto f5 = std::bind(&A::fun_3, a, placeholders::_1, placeholders::_2);
f5(10, 20);
std::function<void(int, int)> fc = std::bind(&A::fun_3, a, std::placeholders::_1, std::placeholders::_2);
fc(10, 20);
return 0;
}
|