精华内容
下载资源
问答
  • callback
    千次阅读
    2021-03-01 12:24:33

    TLS回调函数

    TLS回调函数是指,每当创建/终止进程的线程时会自动调用执行的函数(前后共调用两次)。创建进程的主线程时也会自动调用回调函数,且其调用执行先于EP代码。

    TLS回调函数的声明:

    void NTAPI TLS_CALLBACK(PVOID DllHandle, DWORD Reason, PVOID Reserved)
    

    DllMain的声明:

    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    

    可以看到两者声明非常相似,第一个参数为模块句柄,即加载地址,第二个参数为调用原因

    调用原因有四种

    #define DLL_PROCESS_ATTACH 1
    #define DLL_THREAD_ATTACH 2
    #define DLL_THREAD_DETACH 3
    #define DLL_PROCESS_ATTACH 0
    

    TlsTest.cpp

    #include <windows.h>
    
    //告知连接器使用TLS
    #pragma comment(linker, "/INCLUDE:__tls_used")
    
    void print_console(char* szMsg)
    {
        HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    	//先于主线程调用执行的TLS回调函数中使用printf可能会发生Runtime Error,可直接调用WriteConsole API
        WriteConsoleA(hStdout, szMsg, strlen(szMsg), NULL, NULL);
    }
    
    void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved)
    {
        char szMsg[80] = {0,};
        wsprintfA(szMsg, "TLS_CALLBACK1() : DllHandle = %X, Reason = %d\n", DllHandle, Reason);
        print_console(szMsg);
    }
    
    void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved)
    {
        char szMsg[80] = {0,};
        wsprintfA(szMsg, "TLS_CALLBACK2() : DllHandle = %X, Reason = %d\n", DllHandle, Reason);
        print_console(szMsg);
    }
    /*
    	注册TLS函数
    	.CRT$XLX的作用
    	CRT表示使用C Runtime 机制
    	X表示表示名随机
    	L表示TLS Callback section
    	X也可以换成B~Y任意一个字符
    */
    #pragma data_seg(".CRT$XLX")
    	//存储回调函数地址
        PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, TLS_CALLBACK2, 0 };
    #pragma data_seg()
    
    DWORD WINAPI ThreadProc(LPVOID lParam)
    {
        print_console("ThreadProc() start\n");
    
        print_console("ThreadProc() end\n");
    
        return 0;
    }
    
    int main(void)
    {
        HANDLE hThread = NULL;
    
        print_console("main() start\n");
    	//创建子线程
        hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
      	//等待子线程结束
        WaitForSingleObject(hThread, 60*1000);
        CloseHandle(hThread);
    
        print_console("main() end\n");
    
        return 0;
    }
    

    主线程调用main前调用TLS回调函数,调用原因为DLL_PROCESS_ATTACH

    子线程启动前调用TLS,原因为DLL_THREAD_ATTACH

    子线程结束后调用TLS,原因为DLL_THREAD_DETACH

    主线程结束后调用TLS的原因为DLL_PROCESS_DETACH

    更多相关内容
  • 本文实例讲述了JS回调函数 callback的理解与使用。分享给大家供大家参考,具体如下: 基本理解一个概念 回调函数回头再调用函数,等主干事情干完了,再回头干分支上的事情。 官方定义 A callback is a function ...
  • mixed preg_replace_callback ( mixed pattern, callback callback, mixed subject [, int limit] ) 本函数的行为几乎和 preg_replace() 一样,除了不是提供一个 replacement 参数,而是指定一个 callback 函数。该...
  • npm i redux-saga-callback 用法 import { putWait , withCallback } from 'redux-saga-callback' ; 用withCallback包装您的传奇发生器 takeEvery ( 'FETCH_USERS' , withCallback ( fetchUsers ) ) ; 如果需要,...
  • 正好学习到java Callback,就整理了一下,希望整理的文章内容对大家有所帮助
  • 主要介绍了理解javascript中的回调函数(callback),本文着重于对回调函数概念的理解,需要的朋友可以参考下
  • AjaxCallBack

    2021-03-27 17:49:41
    AjaxCallBack
  • 而这边页面中会出现多个不同JSONP请求,但他们的回调函数名称都是同一个,_Callback。想到设置AJAX 的JSONP参数。但是发现根本不起作用。最后偶然发现 jsonpcallback是区分大小写的。必须是 jsonpCallback 而不是...
  • git-Callback

    2021-03-27 13:58:27
    git-Callback
  • 主要介绍了JavaScript中使用Callback控制流程介绍,本文讲解了callback的一些问题和优化后的写法并给出代码实例,需要的朋友可以参考下
  • callback-开源

    2021-05-01 06:27:54
    该程序通过电话列表监视特定主题的给定电子邮件地址,然后立即呼叫它们。 需要Skype。
  • 主要介绍了PHP callback函数使用方法和注意事项,本文讲解了callback函数的一些使用技巧和避免事项,并给出了一个使用实例,需要的朋友可以参考下
  • dom-request-callback 允许您使用普通的旧回调处理 Firefox 的对象。 安装 $ npm install dom-request-callback 用法 var handle = require ( 'dom-request-callback' ) var request = navigator . mozApps . ...
  • 主要介绍了JavaScript callback回调函数用法,结合实例形式分析了callback回调函数的概念、功能、应用场景及相关使用技巧,需要的朋友可以参考下
  • 主要记录了Asp.net回调技术Callback的一些知识,感兴趣的朋友可以参考下
  • keras-callback-patch

    2021-03-27 10:43:18
    keras-callback-patch
  • 承诺回电 将promise转换为回调接口安装$ npm install --save promise-to-callback用法var promiseToCallback = require ( 'promise-to-callback' ) ;promiseToCallback ( promise ) ( function ( err , data ) {...}...
  • 易语言Callback数据类型转易语言子程序源码.rar 易语言Callback数据类型转易语言子程序源码.rar 易语言Callback数据类型转易语言子程序源码.rar 易语言Callback数据类型转易语言子程序源码.rar 易语言Callback...
  • Callback数据类型转易语言子程序源码,源码是易语言初级应用教程。
  • Callback数据类型转易语言子程序源码
  • JNI 回调函数 Callback

    2015-05-01 10:53:30
    JNI callback Android
  • callback.zip实现调用

    2019-09-11 17:42:31
    以上实现了在vs编译器中用c++开始编写回调函数,新建dll文件主要为回调函数,同时通过新建vs空项目实现对dll的调用
  • 回调承诺npm install --save fn-callback-promisify用法 import { promisify } from 'fn-callback-promisify' ; const fnObj = { print : ( content , callback ) => { callback ( content === 'fail' ? 'new error'...
  • Evernote iOS x-callback-url 支持 Evernote iOS 应用从 7.5 版开始支持 x-callback-url。 一些应用程序已经在使用这种集成,例如和 。 这是的示例 写了很棒的关于 Evernote iOS 中的 x-callback-url 支持以及我们...
  • vue 函数(二):callback回调函数

    千次阅读 2021-09-09 15:17:33
    这里就体现callback的作用了(准确地说callback并不真的是Javascript里的关键字,只是大家都约定成俗把callback这个单词作为回调函数的默认选择)。看下使用回调函数后的代码: (3)第三步:回调函数写法 var fs = ...

    一、介绍:

    1、前提:在 js 中,函数也是对象,可以赋值给变量,可以作为参数放在函数的参数列表中,如:

    var doSomething = function(a,b){
     return a + b;
    }
    
    console.log(doSomething(2,3));

    2、概念:callback 是一种特殊的函数,这个函数被作为参数传给另一个函数去调用,这样的函数就是回调函数。回调,顾名思义,回头再调。回调与同步、异步并没有直接的联系,回调只是一种实现方式,既可以有同步回调,也可以有异步回调,还可以有事件处理回调和延迟函数回调。

    3、语法:在大多数编程语言中,函数的形参总是从外向内传递参数,但在JS中,如果形参碰到“关键字” callback 则完全相反,它表示从内向外反向调用某个外部函数。

    二、举例

    1、举例介绍:

    (1)第一步:

    var fs = require("fs");
    var c
     
    function f(param) {
        console.log(param)
    }
     
    function writeFile() {
        fs.writeFile('input.txt', 'fs.writeFile 写入文件的内容', function (err) {
            if (!err) {
                console.log("文件写入完成")
                c = 1
            }
        });
    }
     
    c = 0
    writeFile()
    f(c)

    打印结果为0,因为程序运行到writeFile()这一行的时候,是一个比较耗时的IO操作,JS碰到这种操作并不会停在原地一直等待直到函数执行完毕,而是直接运行下一条代码(即f(c)),而此时 c = 1这一行代码其实并没有被执行到,所以打印出来的结果还是0 !,如果希望打印1,可以使用第二步的代码:

    (2)第二步:

    var fs = require("fs");
    var c
     
    function f(param) {
        console.log(param)
    }
     
    function writeFile() { 
        fs.writeFile('input.txt', 'fs.writeFile 写入文件的内容', function (err) {
            if (!err) {
                console.log("文件写入完成")
                c = 1
                f(c)
            }
        });
    }
     
    c = 0
    writeFile() 

    这样结果是对的,但是改成这样并不完美,因为这么做就相当于将f()写死在writeFile()里了,如果此处我想根据不同的场景调用不同的函数还要写几个不同的writeFile(),而他们之间的区别仅仅是最后调用的那个函数不同,这里就体现callback的作用了(准确地说callback并不真的是Javascript里的关键字,只是大家都约定成俗把callback这个单词作为回调函数的默认选择)。看下使用回调函数后的代码:

    (3)第三步:回调函数写法

    var fs = require("fs");
     
    function f(param) {
        console.log(param)
    }
     
    function writeFile(callback) { //callback,表示这个参数不是一个普通变量,而是一个函数
        fs.writeFile('input.txt', 'fs.writeFile 写入文件的内容', function (err) {
            if (!err) {
                console.log("文件写入完成")
                c = 1
                callback(c) // 因为我们传进来的函数名是f(),所以此行相当于调用一次f(c)
            }
        });
    }
    var c = 0
    writeFile(f) // 函数f作为一个参数传进writeFile函数

    经过改造后的代码出现了两次callback,第一个callback出现在writeFile的形参里,起定义的作用,表示这个参数并不是一个普通变量,而是一个函数,即所谓的“以函数为参数”。 第二个callback出现在c = 1下面,表示此处“执行”从形参传递进来的那个函数。这样一来,writeFile()函数在执行完毕之后到底调用哪个函数就变“活”了,如果我们想writeFile()函数执行完之后并不是像第二个例子那样只能调用f(),而是还有别的函数比如说x() y() z(),那么只需要写成 writeFile(x),writeFile(y)... 就行了。PS: 此处并不一定非要写为“callback”,你可以任意写成a,b,c...callback只是一种约定俗成的写法,它明确地告诉代码阅读者:此处是一个回调函数。

    但是这步写法不够简洁,一些函数的形参列表里直接嵌套一个函数的情况,其本质上仍然是回调函数,因为没有了函数名,所以也称匿名函数。看下最终的简化写法:

    (4)第四步:匿名回调函数

    var fs = require("fs");
     
    function writeFile(callback) { 
        fs.writeFile('input.txt', '我是通过fs.writeFile 写入文件的内容', function (err) {
            if (!err) {
                console.log("文件写入完毕!")
                c = 1
                callback(c) 
            }
        });
    }
    var c = 0
    writeFile(function (param) {
        console.log(param)
    })

    这是最简洁的写法,再举几个例子:

    var doit = function(callback)
    {
        var a = 1,
            b = 2,
            c = 3;
        var t = callback(a,b,c);
        return t + 10;
    };
    var d = doit(function(x,y,z){
        return (x+y+z);
    });
    console.log(d);
    export default {
      created() {
        this.testCallBack();
      },
      methods: {
        testCallBack() {
          let param = '测试'
          this.myCallback(param, function (arg1, arg2) {
            alert('这是回调' + arg1 + ' ' + arg2)
          });
        },
        myCallback(param, callback) {
          setTimeout(() => {
            alert(param)
            callback(param, '222');
          }, 1000);
        }
      }
    }
    readImageFile(origin, quality, file) {
          let that = this;
          let fileName = file.name;
          let reader = new FileReader();
          reader.onload = function(evt) {
            let base64File = evt.target.result;
            that.imageCompress(
              base64File,
              origin,
              {
                quality
              },
              function(result) {
                let blobFile = that.dataURLtoBlob(result);
                let compressFile = new window.File([blobFile], fileName, { type: file.type });
                that.uploadFile(compressFile);
              }
            );
          };
          reader.readAsDataURL(file);
        },
        // 压缩图片
        imageCompress(path, Orientation, obj, callback) {
          let img = new Image();
          img.src = path;
          img.onload = function() {
            let that = this;
            // 默认按比例压缩
            let imgWidth = that.width;
            let imgHeight = that.height;
            let scale = imgWidth / imgHeight;
            if (imgWidth > MAX_IMAGE_WIDTH) {
              imgWidth = MAX_IMAGE_WIDTH;
              imgHeight = imgWidth / scale;
            }
            let quality = obj.quality || 0.7; // 默认图片质量为0.7
            // 生成canvas
            let canvas = document.createElement('canvas');
            let ctx = canvas.getContext('2d');
            let anw = document.createAttribute('width');
            let anh = document.createAttribute('height');
    
            anw.nodeValue = imgWidth;
            anh.nodeValue = imgHeight;
            canvas.setAttributeNode(anw);
            canvas.setAttributeNode(anh);
            ctx.drawImage(that, 0, 0, imgWidth, imgHeight);
            // quality值越小,所绘制出的图像越模糊
            let base64 = canvas.toDataURL('image/jpeg', quality);
            // 回调函数返回base64的值
            callback(base64);
          };
        },
    function doSomething(msg, callback){
        alert(msg);
        if(typeof callback == "function") 
        callback();
     } 
    doSomething("回调函数", function(){
        alert("匿名函数实现回调!");
     }); 

     2、常见的回调函数例子:

     三、回调函数中this的指向:callback中的this指向window。可以使用Call和Apply函数来改变this指向,每个Javascript中的函数都有两个方法:Call 和 Apply。这些方法被用来设置函数内部的this对象以及给此函数传递变量。

    举例:

    var clientData = {
        id: 096545,
        fullName: "Not Set",
        //setUsrName是一个在clientData对象中的方法
        setUserName: function (firstName, lastName){
            this.fullName = firstName + " " + lastName;
        }
    } 
    
    function getUserInput(firstName, lastName, callback){
        //code .....
    
        //调用回调函数存储
        callback(firstName, lastName);
    }
    
    getUserInput("Barack","Obama",clientData.setUserName);
    
    console.log(clientData.fullName);  //Not Set
    
    console.log(window.fullName);  //Barack Obama

    在上面的代码中,当clientData.setUsername被执行时,this.fullName并没有设置clientData对象中的fullName属性,它将设置window对象中的fullName属性。

    下面我们看下Apply函数实现,Call函数类似。(call接收的第一个参数为被用来在函数内部当做this的对象,传递给函数的参数被挨个传递。Apply函数的第一个参数也是在函数内部作为this的对象,然而最后一个参数确是传递给函数的值的数组。)

    //注意到我们增加了新的参数作为回调对象,叫做“callbackObj”
    function getUserInput(firstName, lastName, callback ,callbackObj){
             //code .....
    
            callback.apply(callbackObj, [firstName, lastName]);
    }
    
    getUserInput("Barack", "Obama", clientData.setUserName, clientData);
    
    console.log(clientData.fullName); //Barack Obama

    四、回调函数的使用场景:

    1、回调函数经常使用于以下场景:

    • 异步调用(例如读取文件,进行HTTP请求,动态加载js文件,加载iframe资源后,图片加载完成执行回调等等)
    • 事件监听器/处理器
    • setTimeout和setInterval方法
    • 一般情况:精简代码

    2、以异步调用为例,回调函数与异步编程:回调函数是实现异步编程的利器,在程序运行中,当某些请求过程漫长,我们有时没必要选择等待请求完成继续处理下一个任务,这时使用回调函数进行异步处理可以大大提高程序执行效率。例如:AJAX请求。若是使用回调函数进行处理,代码就可以继续进行其他任务,而无需空等。实际开发中,经常在javascript中使用异步调用!下面有个使用AJAX加载XML文件的示例,并且使用了call()函数,在请求对象(requested object)上下文中调用回调函数。

    function fn(url, callback){
     var httpRequest;    //创建XHR
     httpRequest = window.XMLHttpRequest ? new XMLHttpRequest() :   //针对IE进行功能性检测
        window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : undefined;
      
     httpRequest.onreadystatechange = function(){
      if(httpRequest.readystate === 4 && httpRequest.status === 200){  //状态判断
       callback.call(httpRequest.responseXML); 
      }
     };
     httpRequest.open("GET", url);
     httpRequest.send();
    }
     
    fn("text.xml", function(){    //调用函数
     console.log(this);                 / /此语句后输出
    });
     
    console.log("this will run before the above callback.");  //此语句先输出

    五、“回调地狱”问题以及解决方案:许多层级的回调函数堆积以致代码层次过多称为回调地狱。

    展开全文
  • uv_callback 调用其他libuv线程上的函数的模块。 它是uv_async的替代品,但有一些区别: 它支持合并和非合并调用它支持同步和异步调用它支持将参数传递给被调用的函数支持结果通知回调使用范例将进度发送到主线程在...
  • callback例子

    2014-06-14 00:43:14
    这是一个及其简单的但是又实用的callBack
  • callBack&&callBack(res.data.token); 相当于if callBack {callBack()}; 回调函数存在则执行。。。 案例演示 function getAllType(callback){ type = ['fruit','vegatable','cake']; callback&&...
    callBack&&callBack(res.data.token);
    相当于if callBack {callBack()};
    
    回调函数存在则执行。。。

     案例演示

    function getAllType(callback){
        type = ['fruit','vegatable','cake'];
        callback&&callback(type);
    }
    function getTypeMsg(id,callback){
        console.log(id); //fruit
        var type = [];
        type['fruit'] = 1;
        type['vegatable'] = 2;
        type['cake'] = 3;
        $getTypeMsg = type[id]; //1
        callback&&callback($getTypeMsg);
    }
    
    // 箭头函数,回调执行
    getAllType((typeData)=>{
        console.log(typeData) // ["fruit", "vegatable", "cake"]
        getTypeMsg(typeData[0],(typeMsg)=>{
            console.log(typeMsg) //1
        })
    })
    

    展开全文
  • 关于C++ 回调函数(callback) 精简且实用

    千次阅读 多人点赞 2021-08-08 00:30:23
    class ProgramB { public: void FunB1(void (ProgramA::*callback)(), void *context) { printf("I'am ProgramB.FunB1() and be called..\n"); ((ProgramA *)context->*callback)(); } }; int main(int argc, char ...

    1 关于回调函数

    1.1 定义

    回调函数的定义,可以很严(复)谨(杂),也可以很简(随)单(意)。其实与其研究定义,还不如讨论为什么需要回调函数,回调函数能干些啥。
    在我看来,回调函数不是在函数的定义上区别于普通函数,而是在调用的方式有区别,因为归根到底,他们都是代码中芸芸众生的普普通通的函数,即“回调函数”的重点在“回调”这两个字。
    以花钱为例,花钱买衣服叫消费,花钱买股票叫投资,都是花钱,但是方式不同,意义也不同。

    下图列举了普通函数执行和回调函数调用的区别。

    • 对于普通函数,就是按照实现设定的逻辑和顺序执行。
    • 对于回调函数,假设Program A和Program B分别有两个人独立开发。回调函数Fun A2它是由Program A定义,但是由Program B调用。Program B只负责取调用Fun A2,但是不管Fun A2函数具体的功能实现。
      image.png

    1.2 为什么需要回调函数

    因为有这样的使用场景,Fun A2只有在 Fun B1调用时才能执行,有点像中断函数的概念。那可能会有人问,在Program A中不断去查询Fun B1的状态,一旦它被执行了,就让Program A自己去执行Fun A2不行吗?如果你有这样的疑问,说明你已经入门了。
    答案是“可以”,但是这样实现的方案不好。因为整个过程中Program A一直都在查询状态,非常耗资源,查询频率高了费CPU,查询频率低了实时性保证不了,Fun B1都执行好久了你才反应过来,Fun A2的执行就会明显晚于Fun B1了。
    正因为如此,回调函数才登上了舞台。

    如果依然一知半解,可以看这位知乎答主的回答。回调函数(callback)是什么?

    2 如何实现函数回调

    函数的回调并不复杂,把 Fun A2的函数的地址/指针告诉Program B就可以了。
    其实我们在这里要讨论的是在C++中,常用回调函数的类型。
    image.png

    得到函数的地址是其中一个关键步骤。
    普通和函数和类的静态成员函数都分配有确定的函数地址,但是类的普通函数是类共用的,并不会给类的每一个实例都分配一个独立的成员函数,这样就太浪费存储资源了。所以类的非静态函数作为回调函数是有区别的,也是这篇文章想要讨论的重点。

    不过我们还以一步一步来,从简单的开始。

    2.1 普通函数作为回调函数

    #include <iostream>
    
    void programA_FunA1() { printf("I'am ProgramA_FunA1 and be called..\n"); }
    
    void programA_FunA2() { printf("I'am ProgramA_FunA2 and be called..\n"); }
    
    void programB_FunB1(void (*callback)()) {
      printf("I'am programB_FunB1 and be called..\n");
      callback();
    }
    
    int main(int argc, char **argv) {
      programA_FunA1();
    
      programB_FunB1(programA_FunA2);
    }
    

    执行结果:
    image.png
    没有什么可说的,非常简单。

    2.2 类的静态函数作为回调函数

    #include <iostream>
    
    class ProgramA {
     public:
      void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); }
    
      static void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); }
    };
    
    class ProgramB {
     public:
      void FunB1(void (*callback)()) {
        printf("I'am ProgramB.FunB1() and be called..\n");
        callback();
      }
    };
    
    int main(int argc, char **argv) {
      ProgramA PA;
      PA.FunA1();
    
      ProgramB PB;
      PB.FunB1(ProgramA::FunA2);
    }
    

    执行结果
    image.png

    可以看出,以上两种方式没有什么本质的区别。
    但这种实现有一个很明显的缺点:static 函数不能访问非static 成员变量或函数,会严重限制回调函数可以实现的功能。

    2.3 类的非静态函数作为回调函数

    #include <iostream>
    
    class ProgramA {
     public:
      void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); }
    
      void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); }
    };
    
    class ProgramB {
     public:
      void FunB1(void (ProgramA::*callback)(), void *context) {
        printf("I'am ProgramB.FunB1() and be called..\n");
        ((ProgramA *)context->*callback)();
      }
    };
    
    int main(int argc, char **argv) {
      ProgramA PA;
      PA.FunA1();
    
      ProgramB PB;
      PB.FunB1(&ProgramA::FunA2, &PA);  // 此处都要加&
    }
    

    执行结果
    image.png
    这种方法可以得到预期的结果,看似完美,但是也存在明显不足。
    比如在programB中FunB1还使用 programA的类型,也就我预先还要知道回调函数所属的类定义,当programB想独立封装时就不好用了。

    这里还有一种方法可以避免这样的问题,可以把非static的回调函数 包装为另一个static函数,这种方式也是一种应用比较广的方法。

    #include <iostream>
    
    class ProgramA {
     public:
      void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); }
    
      void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); }
    
      static void FunA2Wrapper(void *context) {
        printf("I'am ProgramA.FunA2Wrapper() and be called..\n");
        ((ProgramA *)context)->FunA2();  // 此处调用的FunA2()是context的函数, 不是this->FunA2()
      }
    };
    
    class ProgramB {
     public:
      void FunB1(void (ProgramA::*callback)(), void *context) {
        printf("I'am ProgramB.FunB1() and be called..\n");
        ((ProgramA *)context->*callback)();
      }
    
      void FunB2(void (*callback)(void *), void *context) {
        printf("I'am ProgramB.FunB2() and be called..\n");
        callback(context);
      }
    };
    
    int main(int argc, char **argv) {
      ProgramA PA;
      PA.FunA1();
    
      ProgramB PB;
      PB.FunB1(&ProgramA::FunA2, &PA);  // 此处都要加&
    
      printf("\n");
      PB.FunB2(ProgramA::FunA2Wrapper, &PA);
    }
    

    执行结果:
    image.png
    这种方法相对于上一种,ProgramB中没有ProgramA的任何信息了,是一种更独立的实现方式。
    FunB2()通过调用FunA2Wrapper(),实现间接的对FunA2()的调用。FunA2()可以访问和调用对类内的任何函数和变量。多了一个wrapper函数,也多了一些灵活性。

    上面借助wrapper函数实现回调,虽然很灵活,但是还是不够优秀,比如:
    1)多了一个不是太有实际用处的wrapper函数。
    2)wrapper中还要对传入的指针进行强制转换。
    3)FunB2调用时,不但要指定wrapper函数的地址,还要传入PA的地址。

    那是否有更灵活、直接的方式呢?有,可以继续往下看。

    3 std::funtion和std::bind的使用

    std::funtion和std::bind可以登场了。
    std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda表达式、函数指针、以及其它函数对象等[1]。
    std::bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的[2]。
    关于他们的详细用法可以自行百度,如果有需要的以后出一期单独写,这里直接上代码,看std::funtion和std::bind如何在回调中使用。

    #include <iostream>
    
    #include <functional> // fucntion/bind
    
    class ProgramA {
     public:
      void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); }
    
      void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); }
    
      static void FunA3() { printf("I'am ProgramA.FunA3() and be called..\n"); }
    };
    
    class ProgramB {
      typedef std::function<void ()> CallbackFun;
     public:
       void FunB1(CallbackFun callback) {
        printf("I'am ProgramB.FunB2() and be called..\n");
        callback();
      }
    };
    
    void normFun() { printf("I'am normFun() and be called..\n"); }
    
    int main(int argc, char **argv) {
      ProgramA PA;
      PA.FunA1();
    
      printf("\n");
      ProgramB PB;
      PB.FunB1(normFun);
      printf("\n");
      PB.FunB1(ProgramA::FunA3);
      printf("\n");
      PB.FunB1(std::bind(&ProgramA::FunA2, &PA));
    }
    

    执行输出:
    image.png
    std::funtion支持直接传入函数地址,或者通过std::bind指定。
    简而言之,std::funtion是定义函数类型(输入、输出),std::bind是绑定特定的函数(具体的要调用的函数)。

    相比于wrapper方法,这个方式要更直接、简洁很多。

    Ref:

    [1] https://blog.csdn.net/u013654125/article/details/100140328
    [2] https://blog.csdn.net/u013654125/article/details/100140547

    展开全文
  • VC++ CALLBACK

    2014-06-07 11:10:15
    一个例子演示如何在VC++中用函数指针实现回调。 完整文章见我的blog: http://blog.csdn.net/lincyang/article/details/29175413

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 720,323
精华内容 288,129
关键字:

callback

友情链接: 0.96OLED.zip