C++ 定义一个新的类型并调用回调函数

1。

今天学习muduo网络库源码的时候看到了boost::function,写篇笔记记录下。

书上是这样描述的:function是一个函数对象的“容器”,概念上像是C/C++中函数指针类型的泛华,是一种“智能函数指针”。它以对象的形式封装了原始的函数指针或函数对象,能够容纳任意符合函数签名的可调用对象。因此,它可以被用于回调机制,暂时保管函数或函数对象,在之后需要的时机在调用,使回调机制拥有更多弹性。

理解被存函数的最佳方法是把它想象为一个普通的函数对象(也可以想成一个模板类,使用的时候指定函数原型),该函数对象用于封装另一个函数(或函数对象)。这个被存的函数的最大用途是它可以被多次调用,而无须在创建 function 时立即使用。在声明 functions 时,声明中最重要的部分是函数的签名。这部分即是告诉 function 它将保存的函数或函数对象的签名和返回类型。这里有一个完整的程序,程序声明了一个 boost::function ,它可以保存返回 bool (或某个可以隐式转换为 bool 的类型)并接受两个参数的类函数实体,第一个参数可以转换为 int, 第二个参数可以转换为 double.
 

#include <iostream>
#include "boost/function.hpp"
 
bool some_func(int i,double d) {
  return i>d;
}
 
int main() {
  boost::function<bool (int,double)> f;    //bool指定返回类型,(xx,xx)指定参数类型
  f=&some_func;
  f(10,1.1);
}

 

回调的基础

我们先来看看在没有 Boost.Function 以前我们如何实现一个简单的回调,然后再把代码改为使用 function, 并看看会带来什么优势。我们从一个支持某种简单的回调形式的类开始,它可以向任何对新值关注的对象报告值的改变。这里的回调是一种传统的C风格回调,即使用普通函数。这种回调用可用于象GUI控制这样的场合,它可以通知观察者用户改变了它的值,而不需要对监听该信息的客户有任何特殊的知识。

#include <iostream>
#include <vector>
#include <algorithm>
#include "boost/function.hpp"

void print_new_value(int i) {
  std::cout << 
    "The value has been updated and is now " << i <<std::endl;
}

void interested_in_the_change(int i) {
  std::cout << "Ah, the value has changed./n "<<i<<std::endl;
}

class notifier {
  //返回类型(*函数名)(参数表) 
  //形式2:typedef  返回类型(*新类型)(参数表)
  typedef void (*function_type)(int);
  std::vector<function_type> vec_;
  int value_;
public:
  void add_observer(function_type t) {
    vec_.push_back(t);
  }

  void change_value(int i) {
    value_=i;
    for (std::size_t i=0;i<vec_.size();++i) {
      (*vec_[i])(value_);
      std::cout<<"i is  "<<i <<std::endl;
      std::cout<<"vec_.size()  is  "<<vec_.size() <<std::endl;
    }
  }
};

int main() {
  notifier n;
  n.add_observer(&print_new_value);
  n.add_observer(&interested_in_the_change);
  std::cout<<"##################"<<std::endl;

  n.change_value(42);
}

这里的两个函数,print_new_value 和 interested_in_the_change, 它们的函数签名都兼容于 notifier 类的要求。这些函数指针被保存在一个 vector 内,并且无论何时它的值被改变,这些函数都会在一个循环里被调用。调用这些函数的一种语法是:

(*vec_[i])(value_);

值(value_)被传递给解引用的函数指针(即 vec_[i] 所返回的)。另一种写法也是有效的,即这样:

vec_[i](value_);

这种写法看起来更好看些,但更为重要的是,它还可以允许你把函数指针更换为 Boost.Function 而没有改变调用的语法。现在,工作还是正常的,但是,唉,函数对象不能用于这个 notifier 类。事实上,除了函数指针以外,别的任何东西都不能用,这的确是一种局限。但是,如果我们使用 Boost.Function,它就可以工作。重写这个notifier 类非常容易。

首先要做的事是,把 typedef 改为代表 boost::function 而不是函数指针。之前,我们定义的是一个函数指针;现在,我们使用泛型方法,很快就会看到它的用途。接着,我们把成员函数 add_observer 的签名改为泛化的参数类型。我们也可以把它改为接受一个 boost::function,但那样会要求该类的用户必须也知道 function 的使用方法[2],而不是仅仅知道这个观察者类型的要求就行了。应该注意到 add_observer 的这种变化并不应该是转向function 的结果;无论如何代码应该可以继续工作。我们把它改为泛型的;现在,不管是函数指针、函数对象,还是 boost::function 实例都可以被传递给 add_observer, 而无须对已有用户代码进行任何改动。把元素加入到vector 的代码有一些修改,现在需要创建一个 boost::function<void(int)> 实例。最后,我们把调用这些函数的语法改为可以使用函数、函数对象以及 boost::function 实例[3]。这种对不同类型的类似函数的"东西"的扩展支持可以立即用于带状态的函数对象,它们可以实现一些用函数很难做到的事情。

#include <iostream>
#include <vector>
#include <algorithm>
#include "boost/function.hpp"

void print_new_value(int i) {
  std::cout << 
    "The value has been updated and is now " << i <<std::endl;
}

void interested_in_the_change(int i) {
  std::cout << "Ah, the value has changed./n "<<i<<std::endl;
}

class notifier {
  //typedef void (*function_type)(int);
  typedef boost::function<void(int)> function_type;//function_type 是一个类型
  std::vector<function_type> vec_;
  int value_;
public:
  template <typename T> void add_observer(T t) {
    vec_.push_back(function_type(t));
  }

  void change_value(int i) {
    value_=i;
    for (std::size_t i=0;i<vec_.size();++i) {
      vec_[i](value_);
    }
  }
};

class knows_the_previous_value {
  int last_value_;
public:
  void operator()(int i) {
    static bool first_time=true;
    if (first_time) {
      last_value_=i;
      std::cout << 
        "This is the first change of value, so I don't know the previous one./n";
      first_time=false;
      return;
    }
    std::cout << "Previous value was " << last_value_ << '/n';
    last_value_=i;
  }
};

int main() {
  notifier n;
  n.add_observer(&print_new_value);
  n.add_observer(&interested_in_the_change);
  n.add_observer(knows_the_previous_value());
  std::cout<<"##################"<<std::endl;

  n.change_value(42);
  //std::cout << '/n'<<std::endl;
  n.change_value(30);
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值