• 函数指针和回调函数


    [TOC]

    函数指针

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

    一、函数指针的声明

    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 表示,不能在内部使用该指针改变任何内容,该指针只作为参数传递使用。

  • 相关阅读:
    Xshell 跳板机快速登录脚本按钮
    (一)angularjs5 环境搭建
    Myeclipse 内存溢出解决方法
    php 代码放到服务器上验证码不好用
    表格里面的input在底部
    Smarty忽略大括号
    php富友表单提交接口对接
    php富友接口对接http请求
    js去掉html标签
    删除的时候提示是否删除
  • 原文地址:https://www.cnblogs.com/sherlock-lin/p/11708146.html
Copyright © 2020-2023  润新知