C++开发:信号槽库简介

信号槽是一种用于对象间通信的观察者模式实现,广泛用于事件驱动编程。它实现了松耦合的事件处理系统。

核心概念

  1. 信号(Signal)

    • 事件发射器,不关心谁接收

    • 本质是函数调用接口

    • 示例:button.clicked()

  2. 槽(Slot)

    • 事件处理器,不关心谁触发

    • 可以是任何可调用对象(函数/lambda/成员函数)

    • 示例:void onButtonClick()

  3. 连接(Connection)

    • 建立信号与槽的关联关系

    • 通常返回连接对象用于管理生命周期

工作原理

// 伪代码示例
signal.connect(slot);  // 建立连接
signal.emit(args);    // 触发时调用所有连接的slot

关键特性

特性说明
松耦合信号源和接收方互不知晓
多对多关系一个信号可连接多个槽,一个槽可接收多个信号
线程安全通常提供跨线程调用支持(如Qt的QueuedConnection)
类型安全编译期检查参数类型匹配
自动连接管理对象销毁时自动断开连接

 FastSignals

       FastSignals 是一个 C++ 信号/槽(Signal/Slot)库,类似于 Boost.Signals2 或 Qt 的信号槽机制,但专注于 高性能低开销。它适用于需要高效事件处理的场景,比如游戏引擎、高频交易系统或嵌入式开发。


核心特性

  1. 高性能信号触发

    • 优化了信号发射(emit)和槽函数调用的速度,比传统回调(如函数指针或虚函数)更快。

    • 适合对实时性要求高的场景。

  2. 线程安全支持

    • 可配置为线程安全模式(需用户自行管理锁)。

  3. 灵活的连接方式

    • 支持连接普通函数、类成员函数、lambda 表达式等。

    • 可动态断开(disconnect)槽函数。

  4. 纯头文件库(Header-Only)

    • 无需编译,直接包含头文件即可使用。

  5. 现代 C++ 支持(C++11/14/17+)

    • 基于模板和移动语义实现,避免额外开销。

简单示例

#include <FastSignals/fast_signal.hpp>
#include <iostream>

// 定义一个按钮类,包含一个信号
struct Button {
    FastSignal<void()> onClick; // 无参数的信号
};

// 槽函数
void onButtonClicked() {
    std::cout << "按钮被点击了!" << std::endl;
}

int main() {
    Button button;
    button.onClick.connect(&onButtonClicked); // 连接信号和槽
    button.onClick.emit(); // 触发信号(调用槽函数)
    return 0;
}

libsigc++ 信号/槽库

libsigc++ 是 C++ 的一个高效、类型安全的信号与槽(Signal/Slot)库,广泛应用于 GTK(如 GTKmm)等开源项目中。它提供了一种灵活的方式来实现 观察者模式事件驱动编程,比传统的回调函数更安全、更易用。

1. libsigc++ 核心概念

(1) 信号(Signal)

  • 信号的本质:一个可以触发多个回调函数的对象。

  • 信号的作用:当某个事件发生时,通知所有已连接的槽(Slots)。

  • 示例

    sigc::signal<void(int, int)> signal_button_clicked;

(2) 槽(Slot)

  • 槽的本质:一个可调用对象(函数、成员函数、Lambda、Functor 等)。

  • 槽的作用:当信号触发时,执行相应的逻辑。

  • 示例

    void on_button_clicked(int x, int y) { ... }

(3) 连接(Connection)

  • 连接的作用:绑定信号和槽,使信号触发时能调用槽。

  • 连接的管理

    • 可以手动断开连接(disconnect())。

    • 支持自动断开(当槽所属对象销毁时)。

  • 示例

auto conn = signal_button_clicked.connect(sigc::ptr_fun(on_button_clicked));
conn.disconnect(); // 手动断开

Nano Signals 11 信号库

      Nano Signals 11 是一个超轻量级的 C++11 信号/槽(Signal/Slot)库,以其极简设计和高效性能著称。以下是该库的详细解析:

核心特性

  • 极简头文件实现:仅需单个头文件(nano_signal_slot.hpp)

  • 零依赖:完全基于C++11标准,不依赖Boost/QT等

  • 高性能:优化过的模板实现,调用开销极低

  • 类型安全:编译期类型检查

  • 线程不安全:设计简单不处理线程同步

基本用法

#include "nano_signal_slot.hpp"

// 定义信号
Nano::Signal<void(int, const std::string&)> signal;

// 连接普通函数
void free_func(int i, const std::string& s) { /*...*/ }
signal.connect<&free_func>();

// 连接成员函数
struct MyClass {
    void method(int i, const std::string& s) { /*...*/ }
};
MyClass obj;
signal.connect<MyClass, &MyClass::method>(&obj);

// 触发信号
signal.emit(42, "hello");

实现原理

1 信号存储结构
template <typename... Args>
class Signal {
    std::vector<std::function<void(Args...)>> slots;
};
2 连接机制
  • 使用模板参数捕获可调用对象

  • 存储为std::function对象

  • 直接编译期绑定,无运行时类型检查开销

Nuclex 信号槽系统

Nuclex 是一个轻量级的 C++ 信号槽实现,专注于游戏开发和高性能场景。

核心特性

  1. 极简设计

    • 单头文件实现(通常为 Nuclex/Signals/Signal.h

    • 无外部依赖,纯 C++11/14 实现

  2. 高性能优化

    • 使用模板元编程减少运行时开销

    • 内联函数调用优化

    • 避免虚函数和动态内存分配

  3. 线程模型

    • 默认为非线程安全(高性能模式)

    • 可选线程安全版本(带锁实现)

基本用法示例

#include <Nuclex/Signals/Signal.h>

// 定义信号类型
using ButtonClickSignal = Nuclex::Signals::Signal<void(int x, int y)>;

// 创建信号实例
ButtonClickSignal buttonClicked;

// 连接槽函数(lambda)
auto connection = buttonClicked.Connect([](int x, int y) {
    std::cout << "Clicked at: " << x << ", " << y << std::endl;
});

// 发射信号
buttonClicked.Emit(100, 200);

// 断开连接
connection.Disconnect();

关键技术实现

连接存储结构
template <typename... TArgs>
class Signal {
private:
    using SlotType = std::function<void(TArgs...)>;
    std::vector<SlotType> slots;
};
线程安全版本
template <typename... TArgs>
class ThreadSafeSignal {
    std::mutex mutex;
    std::vector<SlotType> slots;
    // 所有操作带锁
};

Qt信号槽机制

Qt信号槽机制的实现原理基于元对象系统(Meta-Object System),通过编译时的代码生成和运行时的动态连接,实现对象间松耦合的通信。‌ 具体原理可分为以下关键点:

元对象系统与moc编译器

  • 元对象系统是Qt框架的核心‌,为信号槽提供运行时类型信息(RTTI)和动态调用机制:
    • 编译时,Qt的元对象编译器(moc)会解析带有Q_OBJECT宏的类,生成包含信号和槽信息的元对象代码(如moc_*.cpp文件)。
    • 生成的元对象代码包含:
      • 信号和槽的名称、参数类型等信息。
      • 动态查找和调用槽函数所需的映射表

 信号与槽的连接过程

  • 通过QObject::connect()建立动态关联‌:
    1. 发送对象(sender)发出信号时,Qt通过元对象系统查找其关联的槽函数列表。
    2. 信号与槽的参数类型必须严格匹配或兼容,确保安全调用(参数传递通过元对象系统完成)。
    3. 连接方式支持:
    • 一对一:一个信号对应一个槽。
    • 一对多:一个信号触发多个槽。
    • 多对一:多个信号触发同一槽。

 运行时的动态特性

  • 信号触发时自动调用关联槽函数‌:
    • emit发射信号,本质是调用moc生成的信号代理函数,遍历所有连接的槽并执行。
    • 槽函数可设置为同步或异步执行(如跨线程通信时会自动排队)。

    Qt信号槽的核心原理依赖于元对象系统编译时生成代码信息,运行时动态解析和调用,实现了高度解耦的通信模式。

主流第三方库对比

特性Qt信号槽Boost.Signals2libsigc++NanoSignalsNuclex
线程安全可选可选
依赖Qt框架Boost独立
性能中等中等极高极高
自动连接管理是(QObject)是(trackable)分组管理
C++标准要求C++11C++11C++11C++11C++14

适用场景

需要高性能事件处理 的项目(如游戏、实时系统)。
不想引入大型库(如 Boost 或 Qt)的轻量级解决方案。
✔ 现代 C++(C++11 及以上)项目。

Qt应用程序:优先使用原生Qt信号槽

游戏开发:Nuclex或NanoSignals

高频交易系统:Boost.Signals2(线程安全)

嵌入式系统:NanoSignals(零开销)

跨平台库:libsigc++

链接

Boost.Signals2:Chapter 67. Boost.Signals2
Libsigc++:libsigc++ -- The Typesafe Callback Framework for C++: libsigc++
LSignal: GitHub - cpp11nullptr/lsignal: C++ signal and slot system
Nano Signals 11: GitHub - FrankHB/nano-signal-slot: Pure C++11 Signals and Slots
Nano Signals 17: GitHub - NoAvailableAlias/nano-signal-slot: Pure C++17 Signals and Slots
Nuclex: https://devel.nuclex.org/framework/browse/listing.php?repname=Framework&path=/Nuclex.Support.Native/trunk/Include/Nuclex/Support/Events/
Sigs: GitHub - netromdk/sigs: Simple thread-safe signal/slot C++17 include-only library.

FastSignals :GitHub - ispringtech/FastSignals: Easy to use, fast and lightweight C++17 signals and slots library, drop-in replacement for the Boost.Signals2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值