C++ 八种回调函数&&使用回调写一个观察者模式。
·
1. 背景:
在大型的工程项目C++ 工程中, C++ 回调使用的非常多。而回调又很多种书写的形式,让我们来总结一些,并且用回调写一个观察者模式来作为练习。
2. 8 种常见回调。
2.1 C 风格函数指针 (C-style function pointer)
用法:
// 定义函数指针类型:接受 int 返回 void
using CallbackFunc = void (*)(int);
// 接收函数指针作为回调的函数
void process_with_func_ptr(int val, CallbackFunc cb)
{
std::cout << "process_with_func_ptr : val" << val << std::endl;
int ret = val * 20;
cb(ret);
}
// 一个符合 CallbackFunc 签名的普通函数
void my_c_func(int x)
{
std::cout << " [func_ptr] result = " << x << "\n";
}
调用:
// ---- 1. 函数指针 ----
std::cout << "[1] Function pointer:";
process_with_func_ptr(10, my_c_func); // 传入普通函数名
// 最传统的回调方式,参数类型完全由函数签名决定。
// 优点:零开销;缺点:无法捕获状态,类型擦除能力弱。
2.2 std::function(标准函数包装器)
void process_with_std_func(int val, std::function<void(int)> cb)
{
cb(val * 3);
}
process_with_std_func(10, [](int x) { // 直接传 lambda
std::cout << " result = " << x << "\n";
});
// 可存储可调用对象(函数、lambda、函子、bind 表达式等)。
// 优点:类型擦除,灵活;缺点:有轻微运行时开销(堆分配可能)。
2.3 函子 / 函数对象 (Functor / Function Object)
struct MultiplyPrinter
{
int factor; // 内部状态:乘数因子
explicit MultiplyPrinter(int f) : factor(f) {}
// 重载 () 使其成为可调用对象
void operator()(int val) const
{
std::cout << " [functor] result = " << val * factor << "\n";
}
};
process_with_std_func(10, MultiplyPrinter(4)); // 传入临时函子对象
// 重载 operator() 的类,可保存内部状态。
// 优点:可以携带配置/数据;缺点:需要额外定义类。
2.4 Lambda 表达式 (Lambda expression)
auto make_lambda_cb(int multiplier)
{
// [multiplier] 按值捕获外部变量
return [multiplier](int val)
{
std::cout << " [lambda] result = " << val * multiplier << "\n";
};
}
auto cb = make_lambda_cb(5); // 工厂函数返回 lambda
process_with_std_func(10, cb);
// C++11 引入的匿名闭包,可捕获外部变量。
// 优点:语法简洁,捕获灵活(值/引用/move);现代 C++ 首选。
2.5 成员函数回调 (Member function callback)
class Handler
{
public:
// 非静态成员函数:隐式含 this 指针
void on_event(int val)
{
std::cout << " [member] result = " << val * 5 << "\n";
}
// 静态成员函数:不含 this,可当普通函数指针用
static void static_on_event(int val)
{
std::cout << " [static] result = " << val * 6 << "\n";
}
};
Handler h;
// 方式一:std::bind 绑定 this 和占位符
process_with_std_func(10, std::bind(&Handler::on_event, &h, std::placeholders::_1));
// 方式二:用 lambda 包装(更推荐,更清晰)
process_with_std_func(10, [&h](int v)
{ h.on_event(v); });
// 类的非静态成员函数不能直接作为回调,需要用 bind 或 lambda 包装。
// 静态成员函数可以当作普通函数指针使用。
2.6 模板回调 (Template-based callback)
// 编译期多态,通过模板参数推导出可调用类型。
// 优点:零开销,完全内联;缺点:必须是模板函数,实现暴露在头文件。
template <typename Callable>
void process_template(int val, Callable &&cb)
{
cb(val * 7);
}
process_template(10, [](int x)
{ std::cout << " result = " << x << "\n"; });
2.7 异步回调 (Async callback with std::thread)
void async_work(std::function<void(int)> cb)
{
// 在新线程中执行回调
std::thread t([cb]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 模拟耗时
cb(100); });
t.detach(); // 分离线程,不阻塞主线程
}
async_work([](int x)
{ std::cout << " async result = " << x << "\n"; });
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 等异步完成
// 将回调传给另一个线程执行,演示线程安全的基本用法。
// std::thread 构造后立即启动,调用 detach() 让其后台运行。
2.8 事件系统 (Event system with multiple callbacks)
class EventEmitter
{
std::vector<std::function<void(int)>> listeners; // 监听器列表
public:
// 注册一个监听器
void on(std::function<void(int)> listener)
{
listeners.push_back(std::move(listener));
}
// 触发事件,通知所有监听器
void emit(int val)
{
for (auto &cb : listeners)
cb(val);
}
};
EventEmitter emitter;
emitter.on([](int v)
{ std::cout << " listener1 got " << v << "\n"; });
emitter.on([](int v)
{ std::cout << " listener2 got " << v * 2 << "\n"; });
emitter.emit(10); // 触发事件
2.9 总结:
完整代码:
#include <iostream>
#include <functional>
#include <vector>
#include <thread>
#include <chrono>
// ============================================================
// 1. C 风格函数指针 (C-style function pointer)
// 最传统的回调方式,参数类型完全由函数签名决定。
// 优点:零开销;缺点:无法捕获状态,类型擦除能力弱。
// ============================================================
// 定义函数指针类型:接受 int 返回 void
using CallbackFunc = void (*)(int);
// 接收函数指针作为回调的函数
void process_with_func_ptr(int val, CallbackFunc cb)
{
std::cout << "process_with_func_ptr : val" << val << std::endl;
int ret = val * 20;
cb(ret);
}
// 一个符合 CallbackFunc 签名的普通函数
void my_c_func(int x)
{
std::cout << " [func_ptr] result = " << x << "\n";
}
// ============================================================
// 2. std::function(标准函数包装器)
// 可存储可调用对象(函数、lambda、函子、bind 表达式等)。
// 优点:类型擦除,灵活;缺点:有轻微运行时开销(堆分配可能)。
// ============================================================
void process_with_std_func(int val, std::function<void(int)> cb)
{
cb(val * 3);
}
// ============================================================
// 3. 函子 / 函数对象 (Functor / Function Object)
// 重载 operator() 的类,可保存内部状态。
// 优点:可以携带配置/数据;缺点:需要额外定义类。
// ============================================================
struct MultiplyPrinter
{
int factor; // 内部状态:乘数因子
explicit MultiplyPrinter(int f) : factor(f) {}
// 重载 () 使其成为可调用对象
void operator()(int val) const
{
std::cout << " [functor] result = " << val * factor << "\n";
}
};
// ============================================================
// 4. Lambda 表达式 (Lambda expression)
// C++11 引入的匿名闭包,可捕获外部变量。
// 优点:语法简洁,捕获灵活(值/引用/move);现代 C++ 首选。
// ============================================================
auto make_lambda_cb(int multiplier)
{
// [multiplier] 按值捕获外部变量
return [multiplier](int val)
{
std::cout << " [lambda] result = " << val * multiplier << "\n";
};
}
// ============================================================
// 5. 成员函数回调 (Member function callback)
// 类的非静态成员函数不能直接作为回调,需要用 bind 或 lambda 包装。
// 静态成员函数可以当作普通函数指针使用。
// ============================================================
class Handler
{
public:
// 非静态成员函数:隐式含 this 指针
void on_event(int val)
{
std::cout << " [member] result = " << val * 5 << "\n";
}
// 静态成员函数:不含 this,可当普通函数指针用
static void static_on_event(int val)
{
std::cout << " [static] result = " << val * 6 << "\n";
}
};
// ============================================================
// 6. 模板回调 (Template-based callback)
// 编译期多态,通过模板参数推导出可调用类型。
// 优点:零开销,完全内联;缺点:必须是模板函数,实现暴露在头文件。
// ============================================================
template <typename Callable>
void process_template(int val, Callable &&cb)
{
cb(val * 7);
}
// ============================================================
// 7. 异步回调 (Async callback with std::thread)
// 将回调传给另一个线程执行,演示线程安全的基本用法。
// std::thread 构造后立即启动,调用 detach() 让其后台运行。
// ============================================================
void async_work(std::function<void(int)> cb)
{
// 在新线程中执行回调
std::thread t([cb]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 模拟耗时
cb(100); });
t.detach(); // 分离线程,不阻塞主线程
}
// ============================================================
// 8. 事件系统 (Event system with multiple callbacks)
// 观察者模式的简化版:支持注册多个监听器,批量通知。
// ============================================================
class EventEmitter
{
std::vector<std::function<void(int)>> listeners; // 监听器列表
public:
// 注册一个监听器
void on(std::function<void(int)> listener)
{
listeners.push_back(std::move(listener));
}
// 触发事件,通知所有监听器
void emit(int val)
{
for (auto &cb : listeners)
cb(val);
}
};
// ============================================================
// 主函数:依次展示每种回调方式
// ============================================================
int main()
{
std::cout << "=== C++ Callback Demos ===\n\n";
// ---- 1. 函数指针 ----
std::cout << "[1] Function pointer:";
process_with_func_ptr(10, my_c_func); // 传入普通函数名
// ---- 2. std::function ----
std::cout << "[2] std::function:";
process_with_std_func(10, [](int x) { // 直接传 lambda
std::cout << " result = " << x << "\n";
});
// ---- 3. 函子 ----
std::cout << "[3] Functor:";
process_with_std_func(10, MultiplyPrinter(4)); // 传入临时函子对象
// ---- 4. Lambda ----
std::cout << "[4] Lambda:";
auto cb = make_lambda_cb(5); // 工厂函数返回 lambda
process_with_std_func(10, cb);
// ---- 5. 成员函数 ----
std::cout << "[5] Member function:";
Handler h;
// 方式一:std::bind 绑定 this 和占位符
process_with_std_func(10, std::bind(&Handler::on_event, &h, std::placeholders::_1));
// 方式二:用 lambda 包装(更推荐,更清晰)
process_with_std_func(10, [&h](int v)
{ h.on_event(v); });
// ---- 6. 模板 ----
std::cout << "[6] Template:";
process_template(10, [](int x)
{ std::cout << " result = " << x << "\n"; });
// ---- 7. 异步回调 ----
std::cout << "[7] Async (thread): waiting...\n";
async_work([](int x)
{ std::cout << " async result = " << x << "\n"; });
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 等异步完成
// ---- 8. 事件系统 ----
std::cout << "[8] Event system:\n";
EventEmitter emitter;
emitter.on([](int v)
{ std::cout << " listener1 got " << v << "\n"; });
emitter.on([](int v)
{ std::cout << " listener2 got " << v * 2 << "\n"; });
emitter.emit(10); // 触发事件
return 0;
}
3. 观察者模式demo
#include <iostream>
#include <vector>
#include <string>
#include <functional>
#include <algorithm>
#include <memory>
#include <ctime>
// ========== 天气站:观察者模式 (基于 std::function 回调) ==========
// ---- 事件类型 ----
enum class WeatherEvent {
TEMPERATURE_CHANGE,
HUMIDITY_CHANGE,
STORM_WARNING
};
// ---- 主题 (Subject) ----
class WeatherStation {
using Callback = std::function<void(WeatherEvent, double)>;
struct Listener {
int id;
std::string name;
Callback cb;
};
std::vector<Listener> listeners_;
int next_id_ = 0;
double temperature_ = 25.0;
double humidity_ = 60.0;
public:
int subscribe(const std::string& name, Callback cb) {
int id = next_id_++;
listeners_.push_back({id, name, std::move(cb)});
std::cout << " [订阅] " << name << " (id=" << id << ")\n";
return id;
}
void unsubscribe(int id) {
auto it = std::remove_if(listeners_.begin(), listeners_.end(),
[id](const Listener& l) { return l.id == id; });
if (it != listeners_.end()) {
std::cout << " [退订] id=" << id << "\n";
listeners_.erase(it, listeners_.end());
}
}
void notify(WeatherEvent event, double val) {
for (auto& l : listeners_)
l.cb(event, val);
}
void set_temperature(double t) {
temperature_ = t;
std::cout << "\n>>> 温度更新: " << t << "°C\n";
notify(WeatherEvent::TEMPERATURE_CHANGE, t);
if (t > 38.0) {
std::cout << "!!! 触发高温风暴警告 !!!\n";
notify(WeatherEvent::STORM_WARNING, t);
}
}
void set_humidity(double h) {
humidity_ = h;
std::cout << "\n>>> 湿度更新: " << h << "%\n";
notify(WeatherEvent::HUMIDITY_CHANGE, h);
}
};
// ========== 具体观察者 (封装为类) ==========
class PhoneApp {
int listener_id_;
public:
explicit PhoneApp(WeatherStation& ws)
: listener_id_(ws.subscribe("手机天气App",
[](WeatherEvent e, double v) {
switch (e) {
case WeatherEvent::TEMPERATURE_CHANGE:
std::cout << " [手机App] 当前气温 " << v << "°C\n";
break;
case WeatherEvent::HUMIDITY_CHANGE:
std::cout << " [手机App] 当前湿度 " << v << "%\n";
break;
case WeatherEvent::STORM_WARNING:
std::cout << " [手机App] ⚠ 风暴警报!气温 " << v << "°C\n";
break;
}
})) {}
};
class SmartSpeaker {
int listener_id_;
public:
explicit SmartSpeaker(WeatherStation& ws)
: listener_id_(ws.subscribe("智能音箱",
[](WeatherEvent e, double v) {
if (e == WeatherEvent::TEMPERATURE_CHANGE)
std::cout << " [智能音箱] 语音播报:现在温度 " << v << " 度\n";
else if (e == WeatherEvent::STORM_WARNING)
std::cout << " [智能音箱] 🔊 警告:即将迎来恶劣天气!\n";
})) {}
};
class ACController {
int listener_id_;
public:
explicit ACController(WeatherStation& ws)
: listener_id_(ws.subscribe("空调控制器",
[](WeatherEvent e, double v) {
if (e != WeatherEvent::TEMPERATURE_CHANGE) return;
if (v > 35.0)
std::cout << " [空调] 开启制冷,目标 26°C (当前 " << v << "°C)\n";
else if (v < 10.0)
std::cout << " [空调] 开启制热,目标 22°C (当前 " << v << "°C)\n";
else
std::cout << " [空调] 关闭空调 (当前 " << v << "°C 舒适)\n";
})) {}
};
class DataLogger {
std::time_t start_time_;
int listener_id_;
public:
explicit DataLogger(WeatherStation& ws)
: start_time_(std::time(nullptr))
, listener_id_(ws.subscribe("数据记录器",
[this](WeatherEvent e, double v) {
if (e == WeatherEvent::TEMPERATURE_CHANGE)
std::cout << " [数据记录] " << std::time(nullptr) << " 温度=" << v << " (启动后 " << (std::time(nullptr) - start_time_) << "s)\n";
})) {}
};
class RangeObserver {
double low_, high_;
int listener_id_ = -1;
WeatherStation* ws_;
public:
RangeObserver(WeatherStation& ws, const std::string& name, double lo, double hi)
: low_(lo), high_(hi), ws_(&ws) {
listener_id_ = ws.subscribe(name + "(区间" + std::to_string(lo) + "~" + std::to_string(hi) + ")",
[this](WeatherEvent e, double v) {
if (e == WeatherEvent::TEMPERATURE_CHANGE) {
if (v >= low_ && v <= high_)
std::cout << " [区间观察者] 温度 " << v << " 在 [" << low_ << "," << high_ << "] 范围内\n";
else
unsubscribe();
}
});
}
void unsubscribe() {
if (ws_ && listener_id_ >= 0) {
ws_->unsubscribe(listener_id_);
listener_id_ = -1;
}
}
~RangeObserver() { unsubscribe(); }
};
int main() {
std::cout << "=== 观察者模式 (Observer) - 天气站演示 ===\n\n";
WeatherStation station;
// 所有观察者都实例化为类对象
PhoneApp phone_app(station);
SmartSpeaker speaker(station);
ACController ac(station);
DataLogger logger(station);
RangeObserver range_obs(station, "舒适温度监控", 20.0, 30.0);
std::cout << "\n---------------- 模拟天气变化 ----------------\n";
station.set_temperature(28.0);
station.set_humidity(65.0);
station.set_temperature(36.0);
station.set_temperature(40.0);
station.set_temperature(22.0);
station.set_humidity(80.0);
std::cout << "\n=== 演示结束 ===\n";
return 0;
}
更多推荐
所有评论(0)