NS3中回调

来源:互联网 发布:鞍钢职工居家工资算法 编辑:程序博客网 时间:2024/05/16 08:59

在了解NS3回调机制前先学习C/C++中的函数指针

函数指针指的是指向函数的指针(* ptr)

声明形式:

返回类型 (*函数指针名)(函数形參表)(=初始值)

C语言中的函数指针:

int (*p)(int a)=0;int  function(int a){a=0;}a=function;// or 加上地址符&int res=a(12)//类似 function(12)

typedef 返回类型(*函数指针类型名)(函参列表)

typedef int(*callback)(int a)
将函数指针名替换成了类型名即声明了一个新类型:

using namespace std;  typedef void(*FUN)(int,int); //定义函数指针类型    void min(int a,int b);  void max(int a,int b);    void min(int a,int b)  {      int minvalue=a<b?a:b;      std::cout<<"min value is "<<minvalue<<"\n";  }    void max(int a,int b)  {      int maxvalue=a>b?a:b;      std::cout<<"Max value is "<<maxvalue<<"\n";  }  //void test(void (*f)(int a,int b),int a,int b)  void test(FUN f,int a,int b)  {      f(a,b);  }    int main()  {      FUN pFun=NULL; //定义函数指针变量pFun      pFun=&min;          test(min,1,2);      test(&max,1,2);      return 0;  }  

C++语言中的函数指针:

C++与C语言函数指针区别是指向调用类成员函数

class A{public:  int methord(int a);};int (A::*p)(int a)=0;//要加类名p=&A::methord;

回调callback:

编程分为两类:系统编程(system programming)和应用编程(application programming)。所谓系统编程,简单来说,就是编写;而应用编程就是利用写好的各种库来编写具某种功用的程序,也就是应用。系统程序员会给自己写的库留下一些接口,即API(application programming interface,应用编程接口),以供应用程序员使用。所以在抽象层的图示里,库位于应用的底下。

当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用call库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用call传给它的应用层函数,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。

打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,也就是把回调函数传入库函数的动作,称为登记回调函数(to register a callback function)。如下图所示(图片来源:维基百科):
应用层函数A--->call 底层库函数B------>call (back)应用层函数C

可以看到,回调函数通常和应用处于同一抽象层(因为传入什么样的回调函数是在应用级别决定的)。而回调就成了一个高层调用底层,底层再过头来用高层的过程。也是其callbak得名如此的原因。

回调机制提供了非常大的灵活性,图中的库函数改称为中间函数了,这是因为回调并不仅仅用在应用和库之间。任何时候,只要想获得类似于上面情况的灵活性,都可以利用回调。跟直接调用call不同,在回调中,我们利用某种方式,把回调函数像参数一样传入中间函数(实质就是函数指针)。可以这么理解,在传入一个回调函数之前,中间函数是不完整的。换句话说,程序可以在运行时,通过登记不同的回调函数,来决定、改变中间函数的行为。这就比简单的函数调用要灵活太多,举例:

#include<iostream>  using namespace std;  typedef  int (*geteven)(int a);//声明函数指针并声明为新类新geteven  int get2res(int a)  {return 2*a;}  int get4res(int a)  {return 4*a;}    int getOdd(int a,geteven fun){  return 1+fun(a);  }  int main(){  int a=1;  int res;  res=getOdd(a,get2res);//2*k+1  cout<<res<<" ";  res=getOdd(a,get4res);//4*k+1 cout<<res;return 0;}
起始函数即中间函数调用者为main函数,中间函数为getOdd函数,回调函数有两种get2res和get4res,如上所说,中间函数getOdd函数需要起始函数传入参数函数指针才是一个完整函数,,程序可以在运行时,通过登记不同的回调函数(get2res和get4res),最后中间函数完成的功能不一样。

总而言之:调用者A提供的函数来完成功能,借指针传递参数给被调用者B,可以全然不管所比较的数据类型。被调用者B回头调用调用者的函数C,故称其为callback

NS3回调callback:

ns3主要提供Callback类API接口来为用户提供服务 ,分为两步骤:

1用给定的签名声明回调的类型

2回调实例化

Callback 与  MakeCallback是成对出现的,其类型如下

1.  Callback其实类似于“指向函数的指针"Callback模板类: Callback< R, T1, T2, T3, T4, T5, T6, T7, T8, T9 >其中 R为Callback的返回类型,必选T1...T9是Callback的实参,可选,默认值为empty

2. MakeCallback
template<typename T , typename OBJ , typename R , typename T1 >
Callback< R, T1 > ns3::MakeCallback (R(T::*)(T1)      mem_ptr,    OBJ      objPtr)     
模板类MakeCallback的返回值为Callback类型
mem_ptr: class method member pointer
objPtr:  class instance
返回值: a wrapper Callback Build Callbacks for class method members which takes one argument and potentially return a value.

针对静态函数

static doubleCbOne(double a,double b){std::out<<"a="<<a<<"b="<<b<<std::endl;return a;   }int main(int argc,char *argv[]){//返回类型 double//第一个参数 double//第二个参数 doubleCallback<double,double,double> one; //回掉实例化,第一个参数是返回值,第二和第三是参数one = MakeCallback(&CbOne);//讲回调one,通过API MakeCallback()与相应的函数进行匹配NS_ASSERT(!one.IsNull());//检查一下回调one是否为空double retone;retone = one(10.0,20.2);//此时one的功能和CbOne的功能是一样的}

针对类成员函数
class Mycb{public:int CbTwo(double a){std::out<<"a="<<a<<std::endl;return -5;}} //返回类型 int//参数 doubleCallback<int,double> two;Mycb cb;//创建一个回调,并让他指向Mycb::CbTwotwo = MakeCallback(&Mycb::CbTwo,&cb);//与静态函数差别多一个参数,即实例化的cb的地址//调用的时候也就是调用cb的CbTwo函数NS_ASSERT(!two.IsNull());//判断回调two不为空int retTwo;retTwo = two(10.0);NS_ASSERT(retTwo == -5);return 0;}
针对Null的回调

Two = MakeNullCallback<int,double>(); //构建空的回调int retTwo = Two(10.2);







0 0
原创粉丝点击