• NS3-回调



    title: 6、NS中的回调
    tags: NS-3,C++,Simulation,Callback,Function Pointer
    slug: storywriter/upgrade_log
    grammar_mindmap: true
    renderNumberedHeading: true
    grammar_code: true
    grammar_decorate: true
    grammar_mathjax: true


    NS-3中的回调其实就是C 语言基本的函数指针的封装类。

    • 函数行参
    • 类的成员变量

    回调函数是当特定事件或者满足某种条件时(时间超时)被调用,用于对该事件或者条件进行响应,是一种可扩展编程的常用手段。回调的最大好处在于扩展性强。不需要和具体的函数进行绑定,而可以在创建的时候动态决定到底调用那个函数。例如,此时我们不想再调用加法,而想调用乘法,那么可以给A对象实例绑定乘法操作,而无需改变A类的定义。

    NS3中使用回调思想来处理各种协议调用或者追踪系统。

    NS3中的回调(callback.cc)

    NS3中对普通函数、对象的方法、类的静态方法等进行了的封装(Callback对象,其中使用C++的模板来表示对应函数的返回值和参数。其中第一个模板参数表示函数的返回值,其后的模板参数表示函数的参数),在src/core/module/callback.h中实现了回调最多可以添加9个参数。

    NS3中的回调
      普通函数的回调|(FunctorCallbackImpl)
        BoundFunctorCallbackImpl
      方法的回调|(MemPtrCallbackImpl)
       BoundMemPtrCallbackImpl
      具体的实现
      		MakeCallback()
    		MakeBoundCallback()
    

    普通函数的回调(FunctorCallbackImpl)

    • 回调的类型:Callback<对应函数的返回值类型,....>

    • MakeCallback()函数来创建一个回调对象
    Callback<int, int, int> callback = MakeCallback(&add);
    
    /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
    
    #include "ns3/core-module.h"
    
    using namespace ns3;
    
    NS_LOG_COMPONENT_DEFINE ("TryCallback");
    
    class A {
    public:
    	A(Callback<int, int, int> calculator);
    
    	void calculate();
    private:
    	Callback<int, int, int> m_calculator;
    };
    
    A::A (Callback<int, int, int> calculator)
    {
    	m_calculator = calculator;
    }
    
    void
    A::calculate ()
    {
    	int result = m_calculator(5, 6);
    	NS_LOG_UNCOND(result);
    }
    
    int add(int a, int b)
    {
    	return a + b;
    }
    
    int
    main (int argc, char *argv[])
    {
    	A one(MakeCallback(&add));
    	one.calculate();
    }
    

    方法的回调(MemPtrCallbackImpl)

    在C++当中,方法被封装在类或者对象当中,因此其使用方法和普通函数是不同的。因此,NS-3为方法回调专门创建了一个类型MemPtrCallbackImpl。这个类型也可以直接通过MakeCallback()函数来创建,和普通函数回调不同的是,创建方法的回调必须传入具体的对象.

    • 定义回调:
    Callback<Complex, Complex &> m_complexCalculator;
    
    • 创建回调对象:
    Complex first(1, 3);
    Callback<Complex, Complex &> callback = MakeCallback(&Complex::add, &first);
    

    完整程序

    /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
    
    #include <iostream>
    
    #include "ns3/core-module.h"
    
    using namespace ns3;
    
    NS_LOG_COMPONENT_DEFINE ("TryCallback");
    
    class Complex {
    public:
    	Complex(int a, int b);
    	Complex add(Complex & another);
    	friend std::ostream & operator <<(std::ostream & out, Complex & c);
    private:
    	int m_a;
    	int m_b;
    };
    
    Complex::Complex (int a, int b)
    {
    	m_a = a;
    	m_b = b;
    }
    
    Complex Complex::add (Complex & another)
    {
    	int a = m_a + another.m_a;
    	int b = m_b + another.m_b;
    	return Complex(a, b);
    }
    
    std::ostream & operator <<(std::ostream & out, Complex & c) {
    	out << c.m_a << " + " << c.m_b << "i";
    	return out;
    }
    
    class A {
    public:
    	A(Callback<int, int, int> calculator);
    	A(Callback<Complex, Complex &> complexCalculator);
    
    	void calculate();
    	void complexCalculate(Complex b);
    private:
    	Callback<int, int, int> m_calculator;
    	Callback<Complex, Complex &> m_complexCalculator;
    };
    
    A::A (Callback<int, int, int> calculator)
    {
    	m_calculator = calculator;
    }
    
    A::A (Callback<Complex, Complex &> complexCalculator)
    {
    	m_complexCalculator = complexCalculator;
    }
    
    void
    A::complexCalculate (Complex b)
    {
    	Complex result = m_complexCalculator(b);
    	std::cout << result << std::endl;
    }
    
    void
    A::calculate ()
    {
    	int result = m_calculator(5, 6);
    	NS_LOG_UNCOND(result);
    }
    
    int add(int a, int b)
    {
    	return a + b;
    }
    
    int multiply(int a, int b)
    {
    	return a * b;
    }
    
    int
    main (int argc, char *argv[])
    {
    	Complex first(1, 3);
    	Complex second(2, 5);
    
    	A one(MakeCallback(&Complex::add, &first));
    	one.complexCalculate(second);//3+8i
    }
    

    绑定参数的回调(MakeBoundCallback)

    NS-3提供了一种绑定参数的回调,可以在创建回调的时候就给回调绑定好部分参数。绑定的参数,只能从第一个参数开始顺序绑定,不能跳过任何参数

    对于对象的方法,由于对象本身就具有存储数据的能力,就无需绑定参数的回调这个概念。因此,NS-3当中并未提供绑定参数的对象方法的回调。

    /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
    
    #include <iostream>
    
    #include "ns3/core-module.h"
    
    using namespace ns3;
    
    NS_LOG_COMPONENT_DEFINE ("TryCallback");
    
    class A {
    public:
    	A(Callback<int, int> calculator);
    
    	void calculate();
    private:
    	Callback<int, int> m_calculator;
    };
    
    A::A (Callback<int, int> calculator)
    {
    	m_calculator = calculator;
    }
    
    void
    A::calculate ()
    {
    	int result = m_calculator(6);
    	NS_LOG_UNCOND(result);
    }
    
    int add(int a, int b)
    {
    	return a + b;
    }
    
    int multiply(int a, int b)
    {
    	return a * b;
    }
    
    int
    main (int argc, char *argv[])
    {
    	A one(MakeBoundCallback(&add, 8));
    	one.calculate();
    }
    

    判断回调是否绑定函数(Callback::IsNull())

    如果不给回调绑定函数就直接调用,程序会发生异常。

    • 为保证程序的健壮性,NS3中提供了方法Callback::IsNull()来判断回调是否已经绑定函数。
    • 已经给回调绑定函数,再使用完成后,想取消绑定,则可以使用NS-3提供的MakeNullCallback()方法,将回调置空。
    /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
    
    /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
    
    #include <iostream>
    
    #include "ns3/core-module.h"
    
    using namespace ns3;
    
    NS_LOG_COMPONENT_DEFINE ("TryCallback");
    
    class A {
    public:
    	A();
    	A(Callback<int, int, int> calculator);
    
    	void calculate();
    
    	void
    	setCalculator (const Callback<int, int, int>& calculator)
    	{
    		m_calculator = calculator;
    	}
    
    private:
    	Callback<int, int, int> m_calculator;
    };
    
    A::A(){}
    
    A::A (Callback<int, int, int> calculator)
    {
    	m_calculator = calculator;
    }
    
    void
    A::calculate ()
    {
    	if(m_calculator.IsNull()) {
    		NS_LOG_UNCOND("callback is not bind to any function.");
    	} else {
    		int result = m_calculator(6, 8);
    		NS_LOG_UNCOND(result);
    	}
    }
    
    int add(int a, int b)
    {
    	return a + b;
    }
    
    int multiply(int a, int b)
    {
    	return a * b;
    }
    
    int
    main (int argc, char *argv[])
    {
    	A one(MakeCallback(&add));
    	one.calculate();
    	one.setCalculator(MakeNullCallback<int, int, int>()); //构造空回调
    	one.calculate();
    }
    

    回调作为属性(CallbackValue)

    NS-3专门给回调构造了一个属性值类型CallbackValue,并且实现了其访问器和检查器。

    程序演示:

    /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
    
    #include <iostream>
    
    #include "ns3/core-module.h"
    
    using namespace ns3;
    
    NS_LOG_COMPONENT_DEFINE ("TryCallback");
    
    namespace ns3 {
    
      class A : public Object{
      public:
        static TypeId GetTypeId (void);
    
        A();
    
        void calculate();
    
        void
        setCalculator (const Callback<int, int, int>& calculator)
        {
          m_calculator = calculator;
        }
    
      private:
        Callback<int, int, int> m_calculator;
      };
    
      A::A(){}
    
    	TypeId
    	A::GetTypeId (void)
    	{
        static TypeId tid = TypeId ("ns3::A")
          .AddConstructor<A> ()
          .SetParent<Object> ()
          .AddAttribute ("calculator", "help text",
                         CallbackValue (),
                         MakeCallbackAccessor (&A::m_calculator),
                         MakeCallbackChecker ())
    			;
        return tid;
    	}
    
      void
      A::calculate ()
      {
        if(m_calculator.IsNull()) {
          NS_LOG_UNCOND("callback is bind to any function.");
        } else {
          int result = m_calculator(6, 8);
          NS_LOG_UNCOND(result);
        }
      }
    
      int add(int a, int b)
      {
        return a + b;
      }
    
      int multiply(int a, int b)
      {
        return a * b;
      }
    }
    
    int
    main (int argc, char *argv[])
    {
    	Ptr<A> a = CreateObject<A>();//使用智能指针创建一个A类的实例
    	a->SetAttribute("calculator", CallbackValue(MakeCallback(&add)));//为属性calculator指定一个回调函数add
    	a->calculate();
    }
    

    例子中将之前A当中的有参构造函数删除,此时向A当中指定回调的任务现在由属性框架来完成。因此A必须继承Object类,并且实现GetTypeId()方法来使用属性框架。在GetTypeId()方法中,创建了一个属性叫做”calculator”,其绑定到了成员变量m_calculator上,属性值类型为CallbackValue。该属性默认回调值为空,使用了变量访问器和默认检查器。

  • 相关阅读:
    理解HTTP的POST和PUT的区别
    眼见为实 — CSS的overflow属性
    Iconfont的代码使用
    JSP中contentType、pageEncoding和meta charset的区别
    在 webpack 中使用 ECharts
    MVC 中的 ViewModel
    一个简单例子理解C#的协变和逆变
    C#中使用委托、接口、匿名方法、泛型委托实现加减乘除算法
    c#打包文件解压缩
    8种主要排序算法的C#实现 (二)
  • 原文地址:https://www.cnblogs.com/lyszyl/p/12077916.html
Copyright © 2020-2023  润新知