现在的位置: 首页 > 综合 > 正文

c\c++回调函数的介绍(含有函数指针和伪函数——functors)

2013年10月07日 ⁄ 综合 ⁄ 共 4854字 ⁄ 字号 评论关闭
文章目录

 

以前在学校学习回调函数的时候,对其应用没有太多的理解,也感觉不出来它有多大的用处,经过几年的积累,现在想把回调函数的一些应用来总结一下,做到温故而知新吧,后续将推出efftive c++系列和c专家系列,以及算法大规模计算方面,希望能同大家共同进步。(所有代码均通过VS2008编译通过) 

一、概念介绍

 a,c语言中的函数指针:

我们知道在C中,函数名可以作为函数的入口,那么函数指针就是给这个入口地址取了一个别名。例如:


#include "stdafx.h"
#include<iostream>
#include<string>
#include<cassert>
//定义函数sum
int sum(const int& a,const int& b)
{
    assert( (a+b)<INT_MAX && (a+b)>INT_MIN);
    return a+b;
}
int (*psum)(const int&,const int&)=sum;// psum为函数指针
typedef int(*fsum1)(const int&,const int&) ;//第二种定义和使用函数指针
fsum1 psum1= sum; //
int main(void )
{

    int a = 12,b=15;
    int c = psum(a,b);//第一种方式
     int d = psum1(a,b);//第二种方式
     std::cout<<"use psum:"<<c<<std::endl;
    std::cout<<"use psum1:"<<d<<std::endl;
    system("pause");
}

这里要解释的是第二种定义和使用函数指针的方式,我们在底层接口封装的时候会经常用到,这里不再多说。

b ,c++中的函数指针

在c++中,静态函数和全局函数的函数指针其定义和调用方式和c中一样,在这里我要强调一下在C++类成员函数指针

// work.cpp : 定义控制台应用程序的入口点。
//using mutex to realize mutithreads 

#include "stdafx.h"
#include<iostream>
#include<string>
#include<cassert>
class test_class
{
public:
    int do_sum(const int& a,const int& b)// 定义类成员函数
    {
        std::cout<<"do sum of two elements,result:"<<(a+b)<<std::endl;
        return 0;
    }
    int (test_class::*pdo_sum)(const int& ,const int& );
    test_class():a(10),b(20)
    {
        pdo_sum = &test_class::do_sum;//在构造函数中初始化类成员函数指针
    }
private:
    int a,b;
};
int test_sample()//在非类成员函数中调用类成员函数指针
{
    int a = 2,b=45;
    test_class* sample = new test_class;
    (*sample.*sample->pdo_sum)(a,b);
    if(sample != NULL)
        delete sample;
    return 0;
}
int main(void )
{
    test_class* test = new test_class;
    const int a= 13,b=17;
    (*test.*test->pdo_sum)(a,b);//主函数中调用
    if(test != NULL)
    {
        delete test;
    }
    test_sample();// 非类成员函数调用
    system("pause");
    return 0;
}

C,在数组中调用函数指针

可以理解为,把函数指针存在指针数组中,在种手段在大规模测试是经常用到,下面举例说明:

// work.cpp : 定义控制台应用程序的入口点。
//using mutex to realize mutithreads 
#include "stdafx.h"
#include<iostream>
#include<string>
#include<cassert>
//定义函数sum
int sum(const int& a,const int& b)
{
    assert( (a+b)<INT_MAX && (a+b)>INT_MIN);
    return a+b;
}

typedef int(*fsum1)(const int&,const int&) ;//第二种定义和使用函数指针
int main(void )
{
     fsum1* sum_test_arr = new fsum1[2];//给数组分配空间,数组类型为fsum1型,fsum1在前面定义过的函数指针
    fsum1 psum1= sum;
    sum_test_arr[0] = psum1;//把psum1放入数组中
    sum_test_arr[1] = psum1;

    int a = 12,b=15;
    int c = sum_test_arr[0](a,b);//调用
     int d = sum_test_arr[1](a,b);//

     std::cout<<"use sum_test_arr[0]:"<<c<<std::endl;
    std::cout<<"use sum_test_arr[1]:"<<d<<std::endl;
    system("pause");
    return 0;
}

二,回调函数

所谓的回调函数,就是定义某个函数,这个函数本身是用来给其他函数或者是接口调用,声明回调函数的关键词有三个,分别为:_cdecl,_stdcall(这两个都是把函数参数列表压入栈中,就是顺序有差别),_fastcall(这个比较特殊,是把函数参数列表存在寄存器register,如果register空间不足,便自动压入栈中),在这里我要强调的两点是:第一,系统默认的是_cdecl这种声明,第二定义回调函数的时候声明关键词必须保持一致。下面举例说明

a,c语言中回调函数调用定义和调用方法(函数级调用和接口调用两种)

函数级调用:函数级调用是指某个回调函数被某个函数调用下面举例说明

#include "stdafx.h"
#include<iostream>
#include<string>
#include<cassert>
//定义函数sum
#define callback // callback 声明所修饰函数是回调函数 其值可以为空或者是:_cdecl,_stdcall,_fastcall
int callback sum(const int& a,const int& b)
{
    assert( (a+b)<INT_MAX && (a+b)>INT_MIN);
    return a+b;
}

int (*psum)(const int&,const int&)=sum;// psum为函数指针
typedef int(*fsum1)(const int&,const int&) ;//第二种定义和使用函数指针
inline float average (int& a,int& b ,fsum1 psum1)
{
    int c = psum1(a,b);
    return (float)c/2;

}

int main(void )
{
    int a = 12,b=15;
    float e = average(a,b,sum);// average函数调用sum函数(sum函数就是我说的回调函数)
     std::cout<< "use average function:\t"<<e<<std::endl;
    system("pause");
    return 0;
}

 

从上面代码不难看出,函数级别调用回调函数,就是把函数指针类,作为调用函数的参数传入,这里我要强调的一点是:回调函数声明时候最好加上callback标志符,告诉别人你的这个函数是会回调函数,是给接口或者是其他函数调用的,另外callback的值,在函数定义和声明时候要保持一致,_fastcall的声明理论上可以提高回调函数的速度,但是要考虑你代码的情况和硬件配置包括cache值。

接口级别调用:

接口级调用,就是接口调用回调函数。这个在底层类封装的时候经常用到。下面举例说明:

#include "stdafx.h"
#include<iostream>
#include<string>
#include<cassert>
//定义函数sum
#define callback // callback 声明所修饰函数是回调函数 其值可以为空或者是:_cdecl,_stdcall,_fastcall
int callback sum(const int& a,const int& b)
{
    assert( (a+b)<INT_MAX && (a+b)>INT_MIN);
    return a+b;
}


int (*psum)(const int&,const int&)=sum;// psum为函数指针
typedef int(*fsum1)(const int&,const int&) ;//第二种定义和使用函数指针


typedef struct user  //定义用户接口,接口中有fsum1类型
{
    fsum1 lpsum;
    int a;
    int b;
}*puser;


int main(void )
{

    user* USER = new user;
    int a = 12,b=15;

    USER->a = a;//接口初始化
    USER->b = b;
    USER->lpsum = sum ;

    int c = USER->lpsum(a,b);//调用接口

    std::cout<<c<<std::endl;
    system("pause");
    return 0;
}

 

b,c++回调函数

下面介绍c++中的回调函数,c++中静态成员函数和全局函数的回调函数机制和c中的是一样的。这里不再介绍,主要介绍类成员函数回调函数和接口回调函数。

通过类this指针实现回调函数

#include "stdafx.h"
#include<iostream>
#include<string>
#include<cassert>
class TClass
{
public:
    TClass(){}
    TClass(int& rhs1,int& rhs2):a(rhs1),b(rhs2){}
    int sum (const int& a,const int& b){return a+b;}
    static int Wraper_To_Call_Sum(void* p2Object,const int&,const int&);//调用了隐含的this指针
private:
    int a;
    int b;
};
int TClass::Wraper_To_Call_Sum(void* p2Object,const int& a,const int&b)
{
    TClass* myself = (TClass*)p2Object;
    return myself->sum(a,b);
    
}
int call_a_callback_sum(void* p2Object,int(*callback)(void* p2Object,const int& a,const int& b))
{

    return callback(p2Object,4,6);

}
int main(void )
{
    TClass mytest;
    int value1 = 15,value2 = 57;
    int c = mytest.sum(value1,value2);//直接调用类成员函数
    int d = mytest.Wraper_To_Call_Sum(&mytest,value1,value2);//类静态函数调用类成员回调函数
    int e = call_a_callback_sum((void*)&mytest,TClass::Wraper_To_Call_Sum);//非类函数调用类成员回调函数
    std::cout<<c<<"\t"<<d<<"\t"<<e<<std::endl;
    system("pause");
    return 0;
}

 三、functor(函子)调用函数指针(functor国内有人译做仿函数,这里不做深入探究)

functor可以利用c++模板和多态实现对函数指针的封装。因此你可以

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

【上篇】
【下篇】

抱歉!评论已关闭.