C++回调(CallBack)方案

VB.NET中使用委托(Delegate)来注册回调(callback)函数 前些日子捣鼓了下VFW,里面注册回调(callback)函数是通过sendmessage函数实现的,也就是把回调函数的指针作为参数发送给hWnd即可。折腾了不少时间,下面是代码这是C/C++代码 typedef struct videohdr_tag { LPBYTE lpData; DWORD dwBufferLength; DWORD dwBytesUsed; 阅读详情

跟诸如Object Pascal和Ada等其它一些语言不同,C++语言并没有内在地提供一种将类的方法作为回调函数使用的方案。在C语言中,这种回调函数被称作算子(functor),在事件驱动类程序中普遍存在。主要问题基于这样一个事实:某个类的多个实例各自位于内存的不同位置。这就需要在回调的时候不仅需要一个函数指针,同时也需要一个指针指向某个实例本身(译者注:否则回调时便无法知道目前正在操作的是哪个对象,C++类的非静态方法包含一个默认的“参数”:this指针,就是起这种作用的)。所以,针对问题的定义,有一个很直观的解决方法就是使用模板和编译时的实例化及特化。

解决方案

这里的方案只支持一个模板参数,但如果一些能够如愿的话,随着更多的编译器完全实现C++标准,以后将会支持动态的模板参数,比如“…”形式的模板参数列表(参见《C++ Templates, The Complete Guide》),那时,我们就可以可以实现无需全部预定义的参数集合。(文中所有代码的注释为译者加,下同。)

template < class Class, typename ReturnType, typename Parameter >

class SingularCallBack

{

   public:

//指向类成员函数的指针,用他来实现回调函数。

typedef ReturnType (Class::*Method)(Parameter);

    //构造函数

    SingularCallBack(Class* _class_instance, Method _method)

    {

       class_instance = _class_instance;

       method        = _method;

    };

   

//重载函数调用运算符()

    ReturnType operator()(Parameter parameter)

    {

       return (class_instance->*method)(parameter);

    };

    //与上面的()等价的函数,引入这个函数的原因见下文

    ReturnType execute(Parameter parameter)

    {

       return operator()(parameter);

};

   private:

    Class* class_instance;

    Method method;

};

模板的使用

模板(template)的使用非常方便,模板本身可被实例化为一个对象指针(object pointer)或者一个简单的类(class)。当作为对象指针使用时,C++有另外一个令人痛苦的限制:operator() 不可以在指针未被解引用的情况下调用,对于这个限制,一个简便的但却不怎么优雅的解决方法在一个模板内部增加一个execute方法(method),由这个方法从模板内部来调用operator()。除了这一点不爽之外,实例化SinglarCallBack为一个对象指针将可以使你拥有一个由回调组成的vector,或者任何其他类型的集合,这在事件驱动程序设计中是非常需要的。

假设以下两个类已经存在,而且我们想让methodB作为我们的回调方法,从代码中我们可以看到当传递一个class A类的参数并调用methodB时,methodB会调用A类的output方法,如果你能在stdout上看到"I am class A :D",就说明回调成功了。

class A

{

   public:

    void output()

    {

       std::cout << "I am class A :D" << std::endl;

    };

};

class B

{

   public:

    bool methodB(A a)

    {

       a.output();

       return true;

    }

};

有两种方法可以从一个对象指针上调用一个回调方法,较原始的方法是解引用(dereference)一个对象指针并运行回调方法(即:operator()),第二个选择是运行execute方法。

//第一种方法:

A a;

B b;

SingularCallBack< B,bool,A >* cb;

cb = new SingularCallBack< B,bool,A >(&b,&B::methodB);

if((*cb)(a))

{

   std::cout << "CallBack Fired Successfully!" << std::endl;

}

else

{

   std::cout << "CallBack Fired Unsuccessfully!" << std::endl;

} //第二种方法:

A a;

B b; SingularCallBack< B,bool,A >* cb;

cb = new SingularCallBack< B,bool,A >(&b,&B::methodB);

if(cb->execute(a))

{

   std::cout << "CallBack Fired Successfully!" << std::endl;

}

else

{

   std::cout << "CallBack Fired Unsuccessfully!" << std::endl;

}

下面的代码示范了怎样将一个模板实例化成一个普通的对象并使用之。

A a;

B b;

SingularCallBack< B,bool,A >cb(&b,&B::methodB);

{

   std::cout << "CallBack Fired Successfully!" << std::endl;

}

else

{

   std::cout << "CallBack Fired Unsuccessfully!" << std::endl;

}

更复杂的例子,一个回调模板可以像下面这样使用:

class AClass

{

   public:      AClass(unsigned int _id): id(_id){};

    ~AClass(){};      bool AMethod(std::string str)

     {

        std::cout << "AClass[" << id << "]: " << str << std::endl;

        return true;

     };    private:

    unsigned int id;

}; typedef SingularCallBack < AClass, bool, std::string > ACallBack;

int main()

{

   std::vector < ACallBack > callback_list;

   AClass a1(1);

   AClass a2(2);

   AClass a3(3);

   callback_list.push_back(ACallBack(&a1, &AClass::AMethod));

   callback_list.push_back(ACallBack(&a2, &AClass::AMethod));

   callback_list.push_back(ACallBack(&a3, &AClass::AMethod));

   for (unsigned int i = 0; i < callback_list.size(); i++)

   {

      callback_list[i]("abc");

   }    for (unsigned int i = 0; i < callback_list.size(); i++)

   {

      callback_list[i].execute("abc");

   }    return true;

}

下面这个例子比上面的又复杂一些,你可以混合从同一个公共基类(base class)上继承下来的不同的类到一个容器中,于是你就可以调用位于继承树的最底层的类的方法(most derived method)。(译者注,C++的多态机制)

class BaseClass

{

   public:

     virtual ~BaseClass(){};

     virtual bool DerivedMethod(std::string str){ return true; };

};

class AClass : public BaseClass

{

   public:

     AClass(unsigned int _id): id(_id){};

    ~AClass(){};

     bool AMethod(std::string str)

     {

        std::cout << "AClass[" << id << "]: " << str << std::endl;

        return true;

     };

     bool DerivedMethod(std::string str)

     {

        std::cout << "Derived Method AClass[" << id << "]: " << str << std::endl;

        return true;

     };

   private:

    unsigned int id;

};

class BClass : public BaseClass

{

   public:

     BClass(unsigned int _id): id(_id){};

    ~BClass(){};      bool BMethod(std::string str)

     {

        std::cout << "BClass[" << id << "]: " << str << std::endl;

        return true;

     };      bool DerivedMethod(std::string str)

     {

        std::cout << "Derived Method BClass[" << id << "]: " << str << std::endl;

        return true;

     };

   private:

    unsigned int id;

}; typedef SingularCallBack < BaseClass, bool, std::string > BaseCallBack;

int main()

{

   std::vector < BaseCallBack > callback_list;    AClass a(1);

   BClass b(2);    callback_list.push_back(BaseCallBack(&a, &BaseClass::DerivedMethod));

   callback_list.push_back(BaseCallBack(&b, &BaseClass::DerivedMethod));    for (unsigned int i = 0; i < callback_list.size(); i++)

   {

      callback_list[i]("abc");

   }    for (unsigned int i = 0; i < callback_list.size(); i++)

   {

      callback_list[i].execute("abc");

   }    return true;

}

为简捷起见,与实例的验证(instance validation)相关的必要代码没有被包含进来,在实际的程序设计中,类实例的传递应该基于这样的结构:使用类似智能指针(smart pointer)的包装类。STL(标准模板库)提供了两个极好的选择:aotu_ptr以及它的后继:shared_ptr。 Andrei Alexandrescu所著的《Modern C++ Design》一书也提供了一个面向策略设计(policy design oriented)的智能指针类。这三种方案中各有自己的优缺点,最终由用户自己来决定究竟那一种最适合他们的需要。
 
C/C++ 回调函数 callback 异步编程 C/C++面向对象(OOP)编程-回调函数详解(回调函数、C/C++异步回调、函数指针)-优快云博客。动态函数指针free报错_编程语言-优快云问答。 阅读详情

相关推荐

【c++】回调函数(callback function)

之前没有用过回调函数,这次突然用上,搜了一下其他大佬写的文章,看完之后还是云里雾里,所以决定自己从最简单的入手重新梳理一遍。 1.回调函数的概念 所谓回调函数,就是把其他函数作为自己的参数。 这里涉及到取地址的概念,为了思路不那么乱我们重新梳理一遍: 对于一个参数A,&A是取A的地址; 对于一个地址address,*address是取该地址下的值。 (int* b = &a; 对于...

weixin_41106066的博客 1585

C++中回调函数(CallBack)

一、定义 回调函数就是一个被作为参数传递的函数。在C语言中,回调函数只能使用函数指针实现,在C++、Python、ECMAScript等更现代的编程语言中还可以使用仿函数或匿名函数。 回调函数的使用可以大大提升编程的效率,这使得它在现代编程中被非常多地使用。同时,有一些需求必须要使用回调函数来实现。 最著名的回调函数调用有C/C++标准库stdlib.h/cstdlib中的快速排序函数qsort和二分查找函数bsearch中都会要求的一个与strcmp类似的参数,用于设置数据的比较方法。 二、示例.

jamin_liu_90的博客 3175

ROS C++回调与自旋机制深度解析:从丢帧到实时控制

在机器人操作系统(ROS)中,回调(Callback)与自旋(Spinning)构成事件驱动架构的核心基础——它替代了传统轮询模式,通过注册响应逻辑而非主动查询消息,显著降低CPU开销并提升响应实时性。其底层依赖CallbackQueue调度、线程安全队列管理及多种Spinner策略(如SingleThreaded、MultiThreaded、AsyncSpinner),直接影响消息吞吐、延迟抖动与多传感器同步精度。正确配置queue_size、thread_count、回调优先级及内存生命周期(如Cons

weixin_34056162的博客 383

关于C++ 回调函数(callback) 精简且实用

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

周小逗的博客 5万+

NX二次开发实战:手把手教你搞定BlockUI集列表的C++回调函数(附完整代码)

本文详细介绍了NX二次开发中BlockUI集列表(SetList)的C++回调函数实现方法,包括基础架构解析、回调函数绑定、动态项管理技巧及数据存取最佳实践。通过实战代码示例和调试技巧,帮助开发者高效解决SetList控件开发中的常见问题,提升开发效率。

tgb345678的博客 309

C++中的回调函数

一、回调机制 1.回调定义(小A带着名片D通过途径C找到小B求他帮忙,小B不能立即解决于是收下名片D,之后的某天小B解决了小A的问题后又通过名片D告诉了小A解决方法) 2.回调方法: ①定义一个函数(普通函数即可);②将此函数的地址注册给调用者;③特定的事件或条件发生时,调用者使用函数指针调用回调函数。例如: 二、同步回调和异步回调 举例:假设有两个程序员在写代码,A程序员写底层...

qq_34754747的博客 2485

【译】C++回调(CallBack)方案

steedhorse(晨星)译 文章出处: http://www.partow.net/programming/templatecallback/问题提出 解决方案 模板的使用 可变参数回调模板 未来展望 一条小提示 最终的考量 兼容性 资源 问题提出 跟诸如Object Pascal和Ada等其它一些语言不同,C++语言并没有内在地提供

steedhorse的专栏 7210

c++实现Callback机制

c++实现Callback机制          Callback是这样的一类对象(在这里不能简单的理解为"回调函数"了):你注册一个函数,以及调用它时的参数,希望在满足某个条件时,以这些注册的函数调用这个回调,完成指定的操作。  Callback的出现,本质上是因为很多操作都有异步化的需要---你不知道它什么时候会执行,只需要告诉它,在执行的时候,调用我告诉你的操作即可.尽管

chenglinhust的专栏 4818

C++使用curl_easy_setopt()获取内容不完整

最近在代码中发现一个问题,我们的C++框架中,使用Curl来获取数据,但是若数据长度较多时,获取的数据不完整,只有后半部分,推测是由于接受数据的缓冲区设置过小造成的。后来调大了缓冲区,问题还是没有解决。         在我们的代码中,使用curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_memory_callback);函数来

舒夜无痕--成为更好的自己 9540

C++中回调函数(CallBack)的用法分析

本文实例分析了C++中回调函数(CallBack)的用法。分享给大家供大家参考。具体分析如下: 如果试图直接使用C++的成员函数作为回调函数将发生错误,甚至编译就不能通过。 其错误是普通的C++成员函数都隐含了一个传递函数作为参数,亦即“this”指针,C++通过传递this指针给其成员函数从而实现程序函数可以访问C++的数据成员。这也可以理解为什么C++类的多个实例可以共享成员函数却-有不同的数据成员。由于this指针的作用,使得将一个CALL-BACK型的成员函数作为回调函数安装时就会因为隐含的this指针使得函数参数个数不匹配,从而导致回调函数安装失败。要解决这一问题的关键就是不让thi

配置 Druid 数据源及密码加密-SpringBoot 实战基础

在SpringBoot中配置 Druid 数据源及密码加密的方法前文集成 MyBatis Plus,实现了一组增删改查接口。在启动服务时,从控制台中可以看出 Spring Boot 默认使用 Hikari 作为数据库连接池,Hikari性能很优秀。在国内使用较多的连接池还属阿里开源的 Druid,中文发音为德鲁伊。Druid 结合了 C3P0、DBCP 等 DB 池的优点,同时还加入了日志监控,可以很好的监控 DB 池连接和 SQL 的执行情况。...

m0_67698950的博客 954

C++20线程超时取消:stop_token与jthread源码级解析与实践

在多线程编程中,线程超时与取消是处理并发任务的关键技术,用于避免资源浪费和提升系统响应性。其原理基于协作式取消机制,通过信号传递让线程安全退出,而非强制终止。这一机制的技术价值在于实现资源的确定释放与状态一致性,避免数据竞争和死锁。应用场景广泛,包括任务调度、服务监控、实时计算等需要控制执行时长的场景。C++20通过引入stop_token、stop_source、jthread等组件,将这一模式标准化,并与RAII、条件变量深度集成,显著简化了代码。本文以C++20的stop_token和jthread为

weixin_30536861的博客 211

计量经济学(因果关系探究-空间双重差分模型: 破解空间溢出效应的因果分析工具)

本文介绍了传统双重差分(DID)模型及其局限性,重点阐述了空间DID模型的必要性。传统DID通过组间差分分离干预效应,但无法处理空间溢出效应。空间DID模型引入空间计量方法,包括三种类型:空间自回归模型(SDID-SAR)捕捉因变量溢出,空间误差模型(SDID-SEM)处理残差相关性,空间杜宾模型(SDID-SDM)同时考虑因变量和自变量的空间滞后。模型选择需结合空间相关性检验,适用于环境政策、房地产限购等存在空间交互效应的研究场景。

YBAdvanceFu的博客 2030

《性能压榨:C++20 协程取消机制的零开销优化——利用“原子轮询”与“嵌入式回调”消除 `stop_token` 注册黑洞》

在每秒处理百万次挂起的异步链条中,的生命周期管理往往成为隐形的性能瓶颈。本文将探讨如何通过“分层拦截”策略优化取消开销。我们将引入**快路径轮询(Fast-path Polling)**来消除 90% 的无效注册,并展示如何通过将**嵌入协程帧(In-place Storage)**来消除动态内存分配。通过这种优化,我们将取消检查的开销降至一次原子负载(Atomic Load),从而在保持系统高度响应的同时,维护极致的吞吐性能。

2503_94462563的博客 305

Xilinx VU+系列多DIE FPGA时序约束与跨DIE信号优化策略

本文深入探讨了Xilinx VU+系列多DIE FPGA的时序约束与跨DIE信号优化策略。针对2.5D/3D封装技术带来的时序挑战,详细解析了SLR区域约束、Laguna寄存器配置及跨时钟域约束等关键技术,提供了实用的TCL脚本和RTL优化示例,帮助开发者有效提升设计性能和时序收敛效率。

weixin_29209801的博客 653

从Gotham到Foundry:一文读懂Palantir三大产品线(Gotham/Foundry/Apollo)的核心差异与适用场景

本文深度解析Palantir三大产品线Gotham、Foundry和Apollo的核心差异与适用场景。Gotham专为国防与情报设计,提供军事级安全分析;Foundry是企业数字化转型的通用平台,支持低代码开发;Apollo则是云原生基石,确保系统可靠运行。通过对比产品架构与典型应用,帮助技术决策者根据需求做出明智选择。

weixin_42524499的博客 839

《原子栅栏与接力逻辑:深度融合 C++20 Stop Callback 与原子所有权机制——打造零竞态、高响应性的工业级协程取消架构》

在高并发异步系统中,确保协程句柄恢复操作的原子性是维护系统确定性的唯一途径。本文将展示如何通过的原子交换(exchange)语义,在与之间建立一套排他性的恢复协议。我们将详细剖析“首胜原则(First-to-Resume)”的实现细节,确保无论是任务自然终结还是被外部取消,父协程仅会被唤醒一次,且始终能通过获得正确的状态反馈,从而彻底杜绝因竞态引发的内存崩溃。

2501_94030456的博客 342

OpenRA引擎实战:如何从零开始搭建一个经典RTS游戏模组(附资源包)

本文详细介绍了如何利用开源游戏引擎OpenRA从零开始搭建经典RTS游戏模组。内容涵盖开发环境配置、资源管线处理、YAML规则定义、地图编辑与Lua脚本编写等全流程实战指南,并提供了资源包,帮助开发者和爱好者快速创建属于自己的即时战略游戏世界。

silver的专栏 903

driver_callback_bypass_1909 项目常见问题解决方案

driver_callback_bypass_1909 项目常见问题解决方案 项目基础介绍 driver_callback_bypass_1909 是一个开源项目,旨在研究和移除各种内核回调,主要用于反作弊技术的研究。该项目主要使用 C++ 编程语言,代码运行在 Windows 10 1909 系统下。项目的主要目标是绕过内核回调,以便在反作弊环境中进行更深入的研究和测试。 新手使用注意事项及解决...

gitblog_00623的博客 813

【昇腾】用MindIE(服务化方式)拉起glm4-9b-chat模型问题解决

【昇腾】用MindIE拉起glm4-9b-chat模型问题解决: LLMInferEngine failed to init LLMInferModels ERR: Failed to init endpoint! Please check the service log or console output. Killed make sure the folder's owner has execute permission.

u014448841的博客 5116

家庭弱电最实用的功能,网线面板如何接线

按照规范,我国宽带入户线按B接法,即568B标准,从后面看,从左到右:1橙白,2橙,3绿白,4蓝,5蓝白,6绿,7棕白,8棕,即和水晶头的接法一致。做水晶头的时候,要注意排好线序,把8根线的头剪齐,留下大约1.8公分,插入水晶头的时候,水晶头要尾巴向下,把线插到水晶头的底端,用网线钳子夹紧。具体是:第1脚——橙白、第2脚——橙色、第3脚——绿白、第4脚——蓝色、第5脚——蓝白、第6脚——绿色、第7脚——棕白、第8脚——棕色,除了四根带颜色的线橙、绿、蓝、棕外,每一根白线上都有线标橙、绿、蓝、棕。

qq_43416206的博客 1670

c++回调函数 callback

                                                                      C++中实现回调机制的几种方式 (1)Callback方式 Callback的本质是设置一个函数指针进去,然后在需要需要触发某个事件时调用该方法, 比如Windows的窗口消息处理函数就是这种类型。比如下面的示例代码,我们在Download完成时需要触发一...

谢小军的专栏 5万+

设计智能化的企业并购目标筛选多维度评估模型

企业并购是企业扩张和战略调整的重要手段,其目的在于实现资源的整合、优势互补和效率提升。评估指标单一:传统评估方法主要依赖财务指标,如净利润、市场份额等,忽视了企业其他重要的非财务指标,如品牌价值、客户满意度等。主观性较强:评估过程中,往往依赖于评估人员的经验和直觉,缺乏客观性,导致评估结果可能存在偏差。评估效率低:传统的评估方法通常需要大量的人力和时间,效率较低,难以应对大规模并购项目的需求。因此,设计一种智能化的企业并购目标筛选多维度评估模型,显得尤为必要。

SuperAGI2025 1034

C++中回调(CallBack)的使用方法

回调函数是一个很有用,也很重要的概念。当发生某种事件时,系统或其他函数将会自动调用你定义的一段函数。回调函数在windows编程使用的场合很多,比如Hook回调函数:MouseProc,GetMsgProc以及EnumWindows,DrawState的回调函数等等,还有很多系统级的回调过程。 一般情况下, 我们使用的回调函数基本都是采用C语言风格. 这里介绍一种C++风格的回调对象方法. 采用t

奋斗中拥有 3万+

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

C++学习:回调函数(callback)

C++学习:回调函数(callback)简介: 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应 可能这些概念性的东西不是太好理解,通俗一点,回调函数就是在两个独立函

章飞 _906285288的博客 2万+

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

上一篇: 判断一个类中是否有某种类形
下一篇: c++ 重载决议与可访问性检查
undefined_behavior
博客等级 码龄19年 1粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值