文章

信号槽

信号槽

信号槽

“信号槽”(Signal and Slot)是一种常用于 事件驱动编程 的通信机制,最典型的代表是 Qt 框架中的实现方式。

它的核心思想是:一个对象(信号发送者)发出信号(Signal),另一个对象(槽函数)收到这个信号并作出响应。本质上是 观察者模式 的一种实现形式。

基本概念

名称说明
信号(Signal)某个事件发生时发送的通知
槽(Slot)对应信号的响应函数
连接(connect)将信号和槽绑定起来

信号槽工作流程(以 Qt 为例)

1
connect(sender, SIGNAL(signalName(args)), receiver, SLOT(slotFunction(args)));

sender 对象发出 signalName 信号时,receiverslotFunction 就会被自动调用。

Qt 简单示例

1
2
3
4
5
// 假设有一个按钮和一个响应槽
QPushButton *button = new QPushButton("Click Me");
QObject::connect(button, &QPushButton::clicked, []() {
    qDebug() << "Button clicked!";
});

当按钮被点击时,Qt 内部会自动调用你连接的槽函数(这里是 lambda)。

为什么需要信号槽?

  • 松耦合:发送信号者和接收者之间不需要直接引用对方。
  • 安全性高:信号槽机制是类型安全的(参数类型匹配检查)。
  • 支持一对多、多对一通信
  • 线程安全(Qt 的 signal/slot 跨线程时自动使用事件队列)

信号槽 vs 回调函数

特性信号槽回调函数
类型安全✅ 是❌ 手动保证
多个接收者✅ 支持多个槽❌ 通常只能一个
解耦性✅ 高❌ 较低
易用性✅ 清晰、现代❌ 需要管理函数指针或绑定

跨线程通信(Qt 特有)

1
connect(sender, &Sender::signal, receiver, &Receiver::slot, Qt::QueuedConnection);
  • 当信号和槽位于不同线程时,Qt 使用事件队列自动进行线程同步。

  • 这极大简化了线程间通信的复杂度。

C++ 中自己实现信号槽机制

如果不使用 Qt,也可以用一些轻量级库来实现信号槽,例如:

  • Boost.Signals2
  • Nano-signal-slot(纯头文件)
  • 自己手写(用 std::function + std::vector 存回调)

简化版 C++ 实现:

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
#include <iostream>       // 引入标准输入输出库,用于 std::cout
#include <functional>     // 引入 std::function,用于函数包装
#include <vector>         // 引入 std::vector,用于存储多个槽函数

// Signal 类:实现简易的信号槽机制
class Signal {
public:
    // 连接一个槽函数(slot),传入一个无参、无返回值的函数对象
    void connect(std::function<void()> slot) {
        slots.push_back(slot); // 将槽函数加入 slots 容器
    }

    // 触发信号(emit),调用所有已连接的槽函数
    void emit() {
        for (auto& slot : slots) // 遍历所有槽
            slot();              // 依次调用
    }

private:
    std::vector<std::function<void()>> slots; // 用于保存所有连接的槽函数
};

int main() {
    Signal sig;  // 创建一个信号对象

    // 使用 Lambda 表达式连接一个槽函数
    sig.connect([]() {
        std::cout << "Hello\n";  // 当信号触发时输出 "Hello"
    });

    // 发出信号,自动调用所有连接的槽函数
    sig.emit();  // 输出:Hello
}
本文由作者按照 CC BY 4.0 进行授权