回调本身有多种形式,下面一一介绍
封装式/延迟回调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Task{ public: typedef void (*TaskCallback)(void*); Task():mTaskCallback(NULL),mArg(NULL) {};
void setTaskCallback(TaskCallback cb, void* arg) { mTaskCallback = cb; mArg = arg; }
void handle() { if(mTaskCallback) mTaskCallback(mArg); }
bool operator=(const Task& task) { this->mTaskCallback = task.mTaskCallback; this->mArg = task.mArg; } private: TaskCallback mTaskCallback; void* mArg; };
|
在上面的回调函数定义中,首先定义别名,具体见上,其中void*是一个通用指针,可以指向任何类型数据。为了充分说明,我们定义一个处理函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| struct ConnectionInfo { int socket_fd; std::string client_ip; };
void handle_connection(void* arg) { ConnectionInfo* info = static_cast<ConnectionInfo*>(arg);
printf("Handling connection from IP: %s on socket %d\n", info->client_ip.c_str(), info->socket_fd);
delete info; }
|
接下来通过set方法装载,myTask.setTaskCallback(handle_connection, connectionData);,执行完这步后,myTask 对象内部的 mTaskCallback 指向了 handle_connection 函数,mArg 指向了 connectionData 对象的内存地址。
需要的时候,系统的其他部分(比如一个线程池或者事件循环)只需要调用 Task 对象的 handle() 方法,就可以执行被封装的任务,而无需关心任务具体是什么。
这种模式非常适用于:
1.线程池/任务队列:主线程创建一堆 Task 对象(通过 set 配置好),然后把这些对象扔进一个队列。工作线程不断从队列中取出 Task 对象,并调用它们的 handle() 方法。 2.事件驱动编程:当某个事件发生时,事件循环调用对应事件处理程序(一个 Task 对象)的 handle() 方法。 3.实现解耦:调用 handle() 的代码完全不知道它到底在执行哪个具体函数,它只知道如何执行一个 Task。
普通回调
这种方式就是网上非常常见的,这里不做赘述,贴上gpt代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <stdio.h> #include <stdlib.h>
int compare_integers(const void* a, const void* b) { int val1 = *(int*)a; int val2 = *(int*)b; return (val1 - val2); }
int main() { int numbers[] = {5, 2, 8, 1, 9}; int n = sizeof(numbers) / sizeof(numbers[0]);
qsort(numbers, n, sizeof(int), compare_integers);
for(int i = 0; i < n; i++) { printf("%d ", numbers[i]); } printf("\n");
return 0; }
|
现代C++中的lamda与function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include <iostream> #include <functional> #include <string>
class ModernTask { public: using TaskCallback = std::function<void()>;
ModernTask() = default;
void setTask(TaskCallback cb) { mTaskCallback = cb; }
void handle() { if (mTaskCallback) { mTaskCallback(); } }
private: TaskCallback mTaskCallback; };
struct ConnectionInfo { int socket_fd; std::string client_ip; };
int main() { ModernTask myTask; ConnectionInfo connectionData = {10, "192.168.1.101"};
myTask.setTask([=]() { std::cout << "Handling connection from IP: " << connectionData.client_ip << " on socket " << connectionData.socket_fd << std::endl; });
myTask.handle();
return 0; }
|