一、回调函数的概念

把一个函数的“地址”或“可调用对象”作为参数传递给另一个函数,当这个函数执行到某个特定时机时,再“回过头”调用你提供的函数。

#include <iostream>
using namespace std;

// 回调函数类型:接收一个整数参数的函数
void myCallback(int value) {
    cout << "Callback called! Value = " << value << endl;
}

// 普通函数,接受一个函数指针作为参数
void processData(int data, void (*callback)(int)) {
    cout << "Processing data..." << endl;
    data += 10;
    // 在特定时刻调用回调
    callback(data);
}

int main() {
    processData(5, myCallback);
    return 0;
}

输出:

Processing data...
Callback called! Value = 15

•    processData 是框架或底层库;
•    myCallback 是上层逻辑;
•    你传给别人一个函数指针,别人异步或延迟地再调用回来。

二、C++中几种实现回调的方法

1、传统函数指针

void doSomething(void (*callback)(int));

缺点:类型受限、无法绑定对象、无法捕获上下文。

2、std::function + std::bind(现代 C++ 推荐)

#include <iostream>
#include <functional>
using namespace std;

void doTask(int x, std::function<void(int)> callback) {
    cout << "Working..." << endl;
    callback(x + 10);
}

class Worker {
public:
    void onFinish(int result) {
        cout << "Task finished with result: " << result << endl;
    }
};

int main() {
    Worker w;
    // 可以绑定成员函数
    doTask(5, std::bind(&Worker::onFinish, &w, std::placeholders::_1));

    // 或直接用lambda
    doTask(10, [](int val) {
        cout << "Lambda callback result: " << val << endl;
    });
}

•    支持成员函数、lambda、自由函数;
•    支持捕获外部变量;
•    语法更安全、更灵活;
•    现代C++推荐使用。

3、Lambda表达式作为回调

auto callback = [](int result) {
    std::cout << "Callback result: " << result << std::endl;
};
doTask(42, callback);

//可以直接捕获变量,非常方便:
int base = 100;
doTask(10, [base](int result) {
    std::cout << "Result + base = " << result + base << std::endl;
});

三、回调函数的典型实用场景

1、异步任务完成通知

void downloadFile(const std::string &url, std::function<void(bool)> onComplete);

当下载完成后自动回调 onComplete(true) 或 onComplete(false)。

2、事件驱动

class Button {
public:
    std::function<void()> onClick;
    void click() {
        if (onClick) onClick();
    }
};

int main() {
    Button btn;
    btn.onClick = [](){ std::cout << "Button clicked!" << std::endl; };
    btn.click();
}

模仿了 Qt 的 connect(button, &QPushButton::clicked, ...)。

3、插件系统或策略模式

//通过回调或注册函数实现动态行为切换。

class Logger {
public:
    std::function<void(const std::string&)> output;

    void log(const std::string& msg) {
        if (output)
            output("[LOG] " + msg);
    }
};

int main() {
    Logger logger;

    // 控制台输出
    logger.output = [](const std::string& msg){ std::cout << msg << std::endl; };

    // 文件输出
    // logger.output = [](const std::string& msg){ writeToFile(msg); };

    logger.log("System started");
}

四、在实际项目中的设计模式与回调结合

场景 典型实使用方法
网络通信 异步connect成功/失败---->回调
文件下载 进度、完成回调
线程池 任务结束--->回调通知UI
自定义控件 用户点击、输入--->回调
插件架构 注册接口回调函数
定时任务 到时间调用注册回调

五、最佳实践

1. 优先使用 std::function 取代原始函数指针
• 更安全,可存储 lambda、成员函数。
2. 命名规范
• 一般命名为 onXxx 或 callbackXxx。

std::function<void(int)> onProgress;
std::function<void()> onFinish;

3. 调用前判断是否为空

if (onFinish) onFinish();

4.生命周期管理
•注意:如果对象在回调执行前被销毁,可能导致悬空指针;
•常用方法:使用 std::weak_ptr 或 QObject::deleteLater。

六、真实案例(下载器场景)

#include <iostream>
#include <thread>
#include <functional>
#include <chrono>
using namespace std;

class Downloader {
public:
    std::function<void(int)> onProgress;
    std::function<void()> onFinish;

    void start() {
        std::thread([this]() {
            for (int i = 0; i <= 100; i += 20) {
                std::this_thread::sleep_for(std::chrono::milliseconds(300));
                if (onProgress) onProgress(i);
            }
            if (onFinish) onFinish();
        }).detach();
    }
};

int main() {
    Downloader d;
    d.onProgress = [](int p){ cout << "Progress: " << p << "%" << endl; };
    d.onFinish   = [](){ cout << "Download complete!" << endl; };
    d.start();

    std::this_thread::sleep_for(std::chrono::seconds(2));
}

输出:

Progress: 0%
Progress: 20%
Progress: 40%
Progress: 60%
Progress: 80%
Progress: 100%
Download complete!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐