C++ 回调函数

it2023-06-02  73

一、定义

将(回调)函数指针、或函数对象、或匿名函数作为函数参数传入(中间)函数,在(中间)函数内部需要的位置再调用(回调)函数。

例如:

#include <iostream> // 声明函数指针,函数参数为两个int型,返回值为int型 int (*application)(int, int); //回调函数 int max(int x, int y) { return x >= y ? x : y; } int min(int x, int y) { return x <= y ? x : y; } int minus(int x, int y) { return x - y; } //中间函数 int thirdparty_lib(int x, int y, int(*compute)(int, int)) { // 在中间函数中调用回调函数 return application(x, y); } //主函数 int main(void) { int x = 6; int y = 2; std::cout << "max: " << thirdparty_lib(x, y, max) << std::endl; // max: 6 std::cout << "min: " << thirdparty_lib(x, y, min) << std::endl; // min: 2 std::cout << "minus: " << thirdparty_lib(x, y, minus) << std::endl; // add: 4 return 0; }

更多示例可参见:https://thispointer.com/designing-callbacks-in-c-part-1-function-pointers/

 

二、应用

回调函数的名字比较唬人,是因为有多种理解方式。

a. 可以把回调理解成库反向调用应用层的函数:一般应用场景都是应用层传递参数并调用库(库往往是封装的),但有时库需要反向与应用层交互,根据应用层需求不同实现不同功能,这就需要把应用层中的函数传递给库,即应用层调用别人写的库(中间函数),同时传一个函数(回调函数)给库。因此,回调函数可以看成库与调用者交互的接口,实现了库与应用层的双向交互(一般都是应用层单向调库,回调是库调用应用层的函数)。注意:不要误解成两个函数来回调用的意思。

b. 回头(待会)再调用的意思。callback来源于电话用语:I will call you back later. 回调函数传递给中间函数,但不是马上调用,直到中间函数某处需要时才会调用回调函数。

以上理解体现了回调不同方面的特性,都是正确的理解。 

 

应用举例: 使用lcm订阅消息时调用了lcm库中的subscribe方法,同时传入自定义的回调函数,当接收到指定通道的消息时,lcm库中的subscribe方法自动调用用户自定义的回调函数处理接收到的信息。

例如:

// file: listener.cpp // // LCM example program. // // compile with: // $ gcc -o listener listener.cpp -llcm // // On a system with pkg-config, you can also use: // $ gcc -o listener listener.cpp `pkg-config --cflags --libs lcm` #include <stdio.h> #include <lcm/lcm-cpp.hpp> #include "exlcm/example_t.hpp" class Handler { public: ~Handler() {} void handleMessage(const lcm::ReceiveBuffer* rbuf, const std::string& chan, const exlcm::example_t* msg) { int i; printf("Received message on channel \"%s\":\n", chan.c_str()); printf(" timestamp = %lld\n", (long long)msg->timestamp); printf(" position = (%f, %f, %f)\n", msg->position[0], msg->position[1], msg->position[2]); printf(" orientation = (%f, %f, %f, %f)\n", msg->orientation[0], msg->orientation[1], msg->orientation[2], msg->orientation[3]); printf(" ranges:"); for(i = 0; i < msg->num_ranges; i++) printf(" %d", msg->ranges[i]); printf("\n"); printf(" name = '%s'\n", msg->name.c_str()); printf(" enabled = %d\n", msg->enabled); } }; int main(int argc, char** argv) { lcm::LCM lcm; if(!lcm.good()) return 1; Handler handlerObject; lcm.subscribe("EXAMPLE", &Handler::handleMessage, &handlerObject); while(0 == lcm.handle()); return 0; }

这里的回调函数即类Handler的成员方法handleMessage,回调函数为类的成员方法时调用方式更复杂一些,可参见将类的成员函数作为参数传递: https://www.cnblogs.com/mupiaomiao/p/4904128.html

当接收到发出来的“EXAMPLE"通道时,调用类Handler的成员方法handleMessage处理消息。

其中,LCM类中subscribe方法声明如下:

class LCM { public: template <class MessageType, class MessageHandlerClass> Subscription* subscribe(const std::string& channel, void (MessageHandlerClass::*handlerMethod)(const ReceiveBuffer* rbuf, const std::string& channel, const MessageType* msg), MessageHandlerClass* handler); };

 关于lcm更多信息可参见:https://blog.csdn.net/Cxiazaiyu/article/details/96046536

 

 

最新回复(0)