Stackoverflow中提出了这样一个问题:假设我们实现了一个User类,Library类,现在Library类中utility需要回调User中func方法,总结答案,常见的几种方法如下:

  1. 静态方法:将User类中func方法实现为静态方法,Library类中进行调用。
  2. 虚拟方法:将User类继承至基类Base,Base类中func方法为纯虚函数。
  3. 直接回调:在Library中保存User类指针,utility方法中直接调用。

下面则是非常规方法。

基于tag dispatch的调用方法,利用空类实现标签回调,在注册方法时提供不同的空类模板参数实现不同的调用,代码如下:

template<class T>
struct tag_t {
using type = T;
constexpr tag_t() {}
}; struct ForLibrary;
template <class T> class Library {
public:
T *node = nullptr; Library(T *n):node(n) {} void utility() {
func(tag_t<ForLibrary>(),node);
};
}; class User {
public:
void func() {
cout << "User::func" << endl;
} friend void func(tag_t<ForLibrary>, User *self) {
self->func();
}
};

不得不说,这种方法太妙了,既可以动态变化回调方法(只需修改ForLibrary参数)又无需改变User类实现,而且一切都是静态调用无虚函数开销。

利用模板基类实现静态多态机制,通过在基类中强转类型调用子类方法,实现路由回调,代码如下:

#include <iostream>
#include <functional> template<typename T>
class ICallback {
public:
void callback() {
static_cast<T*>(this)->func();
}
}; class User : public ICallback<User>
{
public: void func(){
std::cout << "User::func" << std::endl;
}
}; template<class T,class F=std::function<void(void)>>
class Library {
private:
T *node;
public:
Library(T* n):node(n) {
} void utility()
{
std::mem_fn(&T::callback)(*node);
} void utility(F func) {
func();
} }; int main()
{
User user;
Library<User> lib(&user);
lib.utility();
lib.utility(std::bind(&User::callback,user)); return ;
}

回调类与实现类相互解耦又能避免虚函数多态。

C++ 回调函数的几种策略的更多相关文章

  1. PHP回调函数的几种用法

    PHP回调函数的实现方法 目录 前言      全局函数的回调      类静态函数的回调      对象的方法的回调      PHP事件模型(观察者模式)的实现思路    前言 最近在开发一个PH ...

  2. 关于transition回调函数的几种写法

    平时工作中经常遇到需要transition动画结束后触发某个功能的问题,但是在映像中好像只见过animate的回调函数, 而transition的很多属性无法在animate中使用,经过一些总结归纳, ...

  3. C++ 回调函数的定义与用法

    一回调函数 我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理.用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函 ...

  4. javascript 函数初探 (四)--- 回调函数

    回调函数 既然函数与任何被赋值给变量的数据是相同的,那么她当然可以像其他数据那样被定义.删除.拷贝,以及当成参数传递给其它函数. 我们定义一个函数,这个函数有两个函数类型的参数,然后他会分别执行这两个 ...

  5. C++回调函数的应用<转自:http://blog.csdn.net/wubin1124/article/details/4386269>

    一回调函数 我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理.用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函 ...

  6. 理解和使用 JavaScript 中的回调函数

    理解和使用 JavaScript 中的回调函数 标签: 回调函数指针js 2014-11-25 01:20 11506人阅读 评论(4) 收藏 举报  分类: JavaScript(4)    目录( ...

  7. C语言的本质(17)——回调函数

    如果函数的参数是一个函数指针,我们可以通过这个函数指针传递一个函数的地址给另外一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数(Callback Function).回调函数不是由 ...

  8. C语言学习及应用笔记之七:C语言中的回调函数及使用方式

    我们在使用C语言实现相对复杂的软件开发时,经常会碰到使用回调函数的问题.但是回调函数的理解和使用却不是一件简单的事,在本篇我们根据我们个人的理解和应用经验对回调函数做简要的分析. 1.什么是回调函数 ...

  9. C++: 带参数回调函数和不带参数的回调函数;

    在C++中,回调函数的应用比较广泛且重要. 通过传递函数指针到其他地方,能够实现远程回调的作用,能够实现远程调用而不需要事件触发信号或者其他机制来实现,方便而快捷: 首先,回调函数有两种形式:  静态 ...

随机推荐

  1. Docker-Compose 一键部署Ningx+.Net Core+Redis集群

    在看该文章前,你需要对Docker有所了解. 1.创建WebApp应用程序 我使用的是.Net Core 1.0.1版本,创建一个MVC应用程序,并添加对Redis的引用.因为这些很基础,也很简单,这 ...

  2. Python学习札记(十四) Function4 递归函数 & Hanoi Tower

    reference:递归函数 Note 1.在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数. eg.计算阶乘: #!/usr/bin/env python3 def ...

  3. Restful Api CRUD 标准示例 (Swagger2+validator)

    为什么要写这篇贴? 要写一个最简单的CRUD 符合 Restful Api    规范的  一个Controller, 想百度搜索一下 直接复制拷贝 简单修改一下 方法内代码. 然而, 搜索结果让我无 ...

  4. oracle 12c 报错 ora-03137 来自客户机的格式错误的TTC包被拒绝

    昨天下午,实施报了一个oracle的报错ora-03137 说是数据库在11g时没有问题,升级到12c 时,就报错了. 本地调试,看到执行完sql后,报异常,如下: 把SqL在12c的数据库执行一下, ...

  5. .net的根目录区别

    很久没搞.net了,时间一场,全忘记了,倒,,, “~/” 是应用程序根目录“/”  也是表示根目录 “./” 是当前目录“../”表示当前目录的上一级目录

  6. gcc,gdb,make学习

    实例学习gcc+gdb+make程序编译.链接.运行时头文件或动态链接库的查找 分四步: 预处理.编译.汇编.链接4steps:preprocess,compile,assemble,link ​

  7. thinkphp3.2.3定时任务 不能获取本模块config, 不能获取本模块的其他配置

    一开始创建就有一个home模块再创建一个Data模块 定时任务在/Application/Common/Conf/crons.php中,这里不讲怎么创建定时任务. Data模块的配置文件路径如下/Ap ...

  8. [Vue]vee-validate的使用——自定义校验规则及校验message

    1.安装vee-validate npm install vee-validate --save 2.main.js里引用vee-validate插件 import Vue from 'vue' im ...

  9. 《Think in Java》(十二)通过异常处理错误

    异常虽然简单,但是很有用!学完这一章还是发现 Java 异常还是有很多可学之处的,比如:异常说明,异常链等.

  10. .Net Core 修改默认的启动端口

    今天无意中发现一个变化,因为很久没看.net core的项目了,发现项目启动的默认端口已经不是5000了,记得很清楚,最早那还是.net core 1.x版本的时候,每次启动都会默认是5000端口号, ...