Sherlock的程序人生

函数指针和回调函数

函数指针

  • 原理上来说,函数指针和变量的指针是一样的,都是指向内存中的某个地址;

一、函数指针的声明

C:
返回值类型 (*函数指针名称)(param 1, param 2, ...);
C++:
返回值类型 (类名::*函数指针名称)(param 1, param 2, ...);

二、函数指针的使用

  • 函数指针作为形参和普通数据指针作为形参相同;
  • 可以使用typedef简写:typedef int(*PFunction)(int);,后面可以使用PFunction声明函数指针;

(1)C语言

  • int (*pf)(int) = NULL;函数指针的声明;
  • int *pf(int);缺了括号,就是返回值为int*的函数;
int fun1(int temp)
{
    return temp + 1;
}
int fun2(int temp)
{
    return temp + 100;
}

void main()
{
    int (*pf)(int) = NULL;	//声明函数指针并初始化为空指针
	//赋值和调用有两种方法
    //法一
    pf = fun1;
    (*pf)(1);	//2
    //法二,建议使用,因为和变量指针使用方法相同
    pf = &fun2;
    pf(1);	//101
}

(2)C++

  • 全局函数可以使用C语言的写法;
  • 只有public权限的函数才能使用函数指针;
  • 使用类名控制的话,会限定函数指针,所以一般不使用,一般使用全局函数或者类的静态成员函数;

类成员写法示例如下:

class TestClass
{
public:
	int Fun1(int temp){	return temp + 1; }
	int Fun2(int temp) const{ return temp + 10; }
	static int Fun3(int temp){ return temp + 100; }
};
//函数指针作为参数
void TestFun(int(*pf)(int), int temp){
	cout<<pf(temp)<<endl;
}
void TestFun2(int(TestClass::*pf)(int), TestClass& a, int temp){
	cout << (a.*pf)(temp) << endl;
}
void TestFun3(int(TestClass::*pf)(int) const, TestClass& a, int temp){
	cout << (a.*pf)(temp) << endl;
}
//调用
void main()
{
    //static
    int(*pstaticf)(int) = NULL;
	pstaticf = TestClass::Fun3;
	cout << pstaticf(1) << endl;	//101
    TestFun(pstaticf, 1);	//101

	TestClass test_calss;
	//normal function
	int(TestClass::*pf)(int) = NULL;
	pf = &TestClass::Fun1;
	cout << (test_calss.*pf)(1) << endl;	//2
    TestFun2(pf, test_calss, 1);	//2

    //const
	int(TestClass::*pConst)(int) const = NULL;
	pConst = &TestClass::Fun2;
	cout << (test_calss.*pConst)(1) << endl;	//11
    TestFun3(pConst, test_calss, 1);	//11
}

三、函数指针作为函数参数

typedef int(*PFunction)(int);
//法一:
PFunction TestFunction();	//可读性强,建议使用
//法二
int(*TestFunction(float))(int);	//读起来复杂

法二说明:

  • TestFunction有形参列表,说明其是一个函数;
  • TestFunction(float)说明该函数形参为float类型;
  • TestFunction前面有*,说明该函数返回一个指针类型;
  • 最后有(int)说明,返回的指针是函数指针,该函数指针有形参,为int形;

回调函数

回调函数就是利用函数指针进行函数的反向调用。

例如:在类A内创建类B的对象,类A调用B的接口,完成一系列动作,并希望在动作的个别节点上通知类A执行状态。类A调用B的接口,很简答,使用B的指针进行普通函数调用即可,但是B如何通知A呢,B的内部又没有A的指针,就需要回调函数,类A将回调函数传给B,B在需要的时候调用回调函数即可。

示例1:

typedef void(*CallFuncation)(int a);
class MyCallBack
{
public:
	MyCallBack() :callbackFunction(NULL), a(0){}
	void SetCallback(CallFuncation callback_function){
		callbackFunction = callback_function;
		callbackData = p_callback_data;
	}
	void Run(){
       	a = 999;
		if (callbackFunction != NULL){
			callbackFunction(a, callbackData);
		}
	}
private:
	CallFuncation callbackFunction;
	int a;
};
void myFun(int temp)
{
	cout << temp << endl;
}
int _tmain()
{
	MyCallBack my_callback;
	my_callback.SetCallback(myFun);

	return 0;
}

这样,MyCallBack在运行过程中将自身的属性传回给了调用者,但是,调用者若使用动态传递参数呢?上例中,需要在输出的结果长加上某个值,或其他参数呢?示例如下:

typedef void(*CallFuncation)(int a, const void* pCallback);
class MyCallBack
{
public:
	MyCallBack() :callbackFunction(NULL), a(999){}
	void SetCallback(CallFuncation callback_function, const void* p_callback_data = NULL){
		callbackFunction = callback_function;
		callbackData = p_callback_data;
	}
	void Run(){
		if (callbackFunction != NULL){
			callbackFunction(a, callbackData);
		}
	}
private:
	CallFuncation callbackFunction;
	const void* callbackData;
	int a;
};
void myFun(int temp, const void* pCallback)
{
	cout << temp << "  " << *(int*)(pCallback) << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
	int my_param = 888;
	MyCallBack my_callback;
	my_callback.SetCallback(myFun, &my_param);
	my_param = 999;
	my_callback.Run();

	int aaa = 123456;
	my_callback.SetCallback(myFun, &aaa);
	my_callback.Run();

	return 0;
}

在设置回调函数的时候,加上一个传递参数的指针,并保存起来,在调用回调函数的时候,再传回去即可。

这里只用const void 表示,不能在内部使用该指针改变任何内容,该指针只作为参数传递使用。

posted @ 2019-10-20 17:05  sherlock_lin  阅读(470)  评论(0编辑  收藏  举报