【C++】回调函数
<h2 id="前言">前言</h2><p>学习回调函数,<strong>回调函数</strong>是通过函数指针或对象调用的函数。</p>
<p>回调函数就是通过函数指针或对象调用的函数,只要能一个函数能够作为参数传入并调用,这个函数就是回调函数。</p>
<pre><code class="language-C++">#include <iostream>
int addCallBack(int a,int b){//回调函数
std::cout <<a+b<<std::endl;
return 0;
}
int main(int argc, char** argv) {
int(*p)(int,int);
p = addCallBack;
p(1,2);
return 0;
}
</code></pre>
<h2 id="为什么使用回调函数">为什么使用回调函数</h2>
<p>前言里直接在main函数调用addCallBack不是更直接吗?为什么要使用函数指针接收addCallBack的地址,再调用呢?</p>
<p>回调函数,通常是为了实现“控制反转”(Inversion of Control), 灵活、分离、 异步与并发。</p>
<ul>
<li>解耦和模块化: 函数与具体的逻辑解耦,可以复用。</li>
</ul>
<pre><code>// 排序算法(不关心具体比较逻辑)
void sort(int* arr, int n, bool(*compare)(int, int)) {
for (int i = 0; i < n-1; i++) {//解耦和模块化
for (int j = i+1; j < n; j++) {
if (compare(arr, arr)) {
std::swap(arr, arr);
}
}
}
}
// 不同的比较策略
bool ascending(int a, int b) { return a > b; }
bool descending(int a, int b) { return a < b; }
int main() {
int data[] = {5, 2, 8, 1, 3};
sort(data, 5, ascending); // 升序
sort(data, 5, descending);// 降序
return 0;
}
</code></pre>
<ul>
<li>异步处理:我不知道什么时候能算完</li>
</ul>
<pre><code class="language-C++">#include <thread>
#include <functional>
#include <iostream>
// 模拟异步任务
void asyncTask(std::function<void(int)> callback) {
std::thread(() {
std::this_thread::sleep_for(std::chrono::seconds(2));
int result = 42;// 模拟计算结果
callback(result);// 完成后通过回调通知
}).detach();
}
// 回调处理结果
void handleResult(int result) {
std::cout << "异步任务完成,结果: " << result << std::endl;
}
int main() {
std::cout << "开始异步任务..." << std::endl;
asyncTask(handleResult);// 非阻塞调用
// 主线程可以继续做其他事情
for (int i = 0; i < 5; i++) {
std::cout << "主线程工作..." << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return 0;
}
</code></pre>
<h2 id="实现">实现</h2>
<h3 id="函数指针实现">函数指针实现</h3>
<h4 id="普通函数调用">普通函数调用</h4>
<pre><code class="language-C++">#include <iostream>
//回调函数 无参
void callBack(){
std::cout<<"无参回调函数"<<std::endl;
}
//回调函数 带参数
void callback_ii(int a,int b){
std::cout<<a+b<<std::endl;
}
//回调函数带返回值
int callback_return_i(){
int a = 10;
return a;
}
/*
定义函数指针
*/
//无参 函数指针
typedef void(*CallbackPtr)();
// 它是"指向返回void,接受两个int参数的函数"的指针类型
typedef void (*CallbackPtr_ii)(int, int);
// using CallbackPtr_using = void(*)(int, int);
//带返回值 函数指针
typedef int(*CallbackPtr_return_i)();
void performTask(CallbackPtr cb) {
cb(); // 执行回调
}
void performTask_ii(int a, int b, CallbackPtr_ii cb) {
// 业务逻辑...
cb(a, b); // 执行回调
}
void performTask_return_i(CallbackPtr_return_i cb) {
// 业务逻辑...
std::cout<< cb() <<std::endl;
}
int main(){
performTask(callBack);
performTask_ii(1,2,callback_ii);
performTask_return_i(callback_return_i);
return 0;
}
</code></pre>
<p>这里其实就是使用指针调用函数。</p>
<blockquote>
<p>void (*p)(int ,int);</p>
<p>p = callback;</p>
<p>//p = &callback;</p>
<p>(*p)(0,1);</p>
<p>//p(0,1);</p>
</blockquote>
<h4 id="类成员函数和类静态函数调用">类成员函数和类静态函数调用</h4>
<pre><code class="language-C++">#include <iostream>
class MyClass {
public:
void Func(){
std::cout << "function" << std::endl;
}
static void staticFunc() {
std::cout << "Static function" << std::endl;
}
};
int main() {
void (*staticFuncPtr)() = &MyClass::staticFunc;
staticFuncPtr();// 输出: Static function
/*
void (*funcPtr)() =&MyClass::Func;//error: cannot convert ‘void (MyClass::*)()’ to ‘void (*)()’ in initialization
funcPtr();
*/
// 指向普通成员函数 - 需要特殊的语法
MyClass MyObj;
void (MyClass::*FuncPtr)() = &MyClass::Func;// 声明成员函数指针
(MyObj.*FuncPtr)();// 通过对象调用,输出: function
return 0;
}
</code></pre>
<h4 id="class-a-调用-class-b">Class A 调用 Class B</h4>
<pre><code class="language-C++">#include <iostream>
class ProgramA {
public:
void Func(void (*callback)()) {
std::cout << "A: callback" << std::endl;
callback();
}
};
class ProgramB {
public:
void Func() {
std::cout << "B: function" << std::endl;
}
static void staticFunc() {
std::cout << "B: Static function" << std::endl;
}
};
int main() {
ProgramA PA;
PA.Func(ProgramB::staticFunc);
return 0;
}
</code></pre>
<ul>
<li>如何使用A调用B中的非静态方法?</li>
</ul>
<p>这里只写两种方式。</p>
<p>方式一:使用function修改A的调用函数。</p>
<p>方式二:在A中修改参数</p>
<pre><code class="language-C++">#include <iostream>
#include <functional>
class ProgramB;
class ProgramA {
public:
//方式一
void Func(std::function<void()> callback) {
std::cout << "A std::function<void(): callback" << std::endl;
callback();
}
//方式二
void Func(void(ProgramB::*callback)(),void *PBPtr){
std::cout << "A void(ProgramB::*callback)(): callback" << std::endl;
((ProgramB*)PBPtr->*callback)();//*不是解引用,而是指针到成员运算符 ->* 的一部分
}
};
class ProgramB {
public:
void Func() {
std::cout << "B: function" << std::endl;
}
static void staticFunc() {
std::cout << "B: Static function" << std::endl;
}
};
int main() {
ProgramA PA;
ProgramB PB;
PA.Func(ProgramB::staticFunc);
PA.Func([&PB](){
PB.Func();
});
PA.Func(&ProgramB::Func,&PB);
return 0;
}
</code></pre>
<h3 id="lambda表达式实现">Lambda表达式实现</h3>
<ul>
<li>Lambda表达式语法</li>
</ul>
<pre><code class="language-C++">[捕获列表](参数列表) mutable exception -> 返回类型 { 函数体 }
</code></pre>
<pre><code>void run(std::function<void()> cb) { cb(); }
int main() {
int secret = 42;
// 使用 Lambda 作为回调,并捕获局部变量 secret
run(() {
std::cout << "数字是: " << secret << std::endl;
});
}
</code></pre>
<h3 id="stdfunction-与-stdbind">std::function 与 std::bind</h3>
<p>C++11 引入的 <code>std::function</code> 是一个<strong>通用函数包装器</strong>。它可以存储、复制和调用任何“可调用对象”(函数指针、仿函数、Lambda、类成员函数</p>
<p>上面已经有关于function的内容,这里总结一下,</p>
<pre><code class="language-C++">#include <iostream>
#include <functional>
class Program {
public:
void func(int status) {
std::cout << "func: " << status << std::endl;
}
static void staticFunc(){
std::cout << "staticFunc" << std::endl;
}
};
void gfunc(){
std::cout << "gfunc" << std::endl;
}
int main() {
//1, 类非静态函数
Program d;
// 绑定对象 d 到成员函数 onFinished
std::function<void(int)> cb_1 = std::bind(&Program::func, &d, std::placeholders::_1);
//std::placeholders::_1 这是一个占位符。
//由于 func(int status) 需要一个整数参数,但我们在绑定时还不知道这个参数的具体值(它要在未来触发回调时才由调用者传入)。
//_1 表示:这个位置的参数,请在未来调用 cb(value) 时,把第一个参数填到这里。
cb_1(200);
//2.类静态函数
std::function<void()> cb_2 = Program::staticFunc;
cb_2();
//3 普通函数
std::function<void()> cb_3 = gfunc;
cb_3();
//
std::function<void()> cb_4 = &gfunc;
cb_4();
}
</code></pre><br><br>
来源:https://www.cnblogs.com/hjk-airl/p/18946018
頁:
[1]