NS3中回调

在了解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 double
CbOne(double a,double b)
{
std::out<<"a="<<a<<"b="<<b<<std::endl;
return a;   
}
int main(int argc,char *argv[])
{
//返回类型 double
//第一个参数 double
//第二个参数 double
Callback<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
//参数 double
Callback<int,double> two;
Mycb cb;
//创建一个回调,并让他指向Mycb::CbTwo
two = 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);







  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值