信息发布→ 登录 注册 退出

c++怎么实现一个简单的信号槽机制_c++信号与槽机制的实现与应用

发布时间:2025-11-02

点击量:
答案:通过std::function和可变模板参数实现支持多类型槽函数的信号机制,具备连接管理与解耦特性。

c++怎么实现一个简单的信号槽机制_c++信号与槽机制的实现与应用

在C++中实现一个简单的信号与槽机制,核心目标是解耦对象之间的通信。Qt框架中的信号槽非常经典,但不依赖Qt时,我们可以通过现代C++(如C++11及以上)的特性,比如std::function可变模板参数std::shared_ptr来实现一个轻量级版本。

基本设计思路

信号(Signal)是一个事件发生的通知者,槽(Slot)是响应这个事件的函数。我们需要做到:

  • 一个信号可以绑定多个槽函数
  • 支持普通函数、成员函数、lambda表达式作为槽
  • 连接管理:能断开连接或自动清理无效连接

这里采用基于std::function存储回调,并用连接ID管理订阅关系。

简易信号类实现

定义一个模板类Signal,支持任意参数的函数签名:

#include <vector>
#include <functional>
#include <algorithm>

template <typename... Args>
class Signal {
private:
    using SlotType = std::function<void(Args...)>;
    std::vector<SlotType> slots_;
    int next_id_ = 0;
    std::vector<int> free_ids_;

public:
    // 连接一个槽函数,返回连接ID
    int connect(SlotType slot) {
        int id;
        if (free_ids_.empty()) {
            id = next_id_++;
            slots_.push_back(slot);
        } else {
            id = free_ids_.back();
            free_ids_.pop_back();
            slots_[id] = slot;
        }
        return id;
    }

    // 断开连接
    void disconnect(int id) {
        if (id >= 0 && id < (int)slots_.size() && slots_[id]) {
            slots_[id] = nullptr;
            free_ids_.push_back(id);
        }
    }

    // 触发信号,调用所有有效槽
    void emit(Args... args) {
        for (const auto& slot : slots_) {
            if (slot) {
                slot(args...);
            }
        }
    }
};

使用示例

下面演示如何连接普通函数、lambda和成员函数:

RhaPHP微信公众号管理系统 RhaPHP微信公众号管理系统

RhaPHP 是一款免费开源的微信公众号管理营销系统!也是一款微信公众号开发框架。简洁,灵活,快速易开发,应用模块化,支持移动端管理微信公众号。基于 THINKPHP5,简单的代码即可实现微信公众号通信与接口实现。不需要花大量时间研究系统即可快速开发微信应用,rhaphp在微信开发有着灵活机制,支持移动管理微信公众号。系统运行环境 PHP+MYSQL。

RhaPHP微信公众号管理系统 2 查看详情 RhaPHP微信公众号管理系统
#include <iostream>

struct Receiver {
    void onEvent(int value) {
        std::cout << "Received: " << value << "\n";
    }
};

void globalCallback(int value) {
    std::cout << "Global handler: " << value << "\n";
}

int main() {
    Signal<int> sig;
    Receiver receiver;

    // 连接全局函数
    int conn1 = sig.connect(globalCallback);

    // 连接lambda
    int conn2 = sig.connect([](int v) {
        std::cout << "Lambda received: " << v << "\n";
    });

    // 连接成员函数(注意捕获receiver实例)
    int conn3 = sig.connect([&receiver](int v) {
        receiver.onEvent(v);
    });

    // 发送信号
    sig.emit(42);

    // 断开某个连接
    sig.disconnect(conn2);

    std::cout << "After disconnecting lambda:\n";
    sig.emit(100);

    return 0;
}

输出结果:

Global handler: 42
Lambda received: 42
Received: 42
After disconnecting lambda:
Global handler: 100
Received: 100

改进方向与注意事项

当前实现简单实用,但可用于生产环境前建议增强以下几点:

  • 线程安全:在多线程环境中,对slots_的访问应加锁(如std::mutex
  • 自动释放:若槽函数持有对象引用,对象销毁后应自动断开连接。可通过std::weak_ptr检测生命周期
  • 连接管理器:引入Connection类,支持RAII自动断开
  • 性能优化:避免频繁内存分配,可用对象池管理连接ID

基本上就这些。这个轻量级信号槽机制适合嵌入小型项目或学习事件驱动编程模型,不复杂但足够灵活。

以上就是c++++怎么实现一个简单的信号槽机制_c++信号与槽机制的实现与应用的详细内容,更多请关注其它相关文章!


相关文章: J*aScript DOM操作:高效清空列表元素的策略与实践  构建轻量级网站内部消息系统:Formspree 集成指南  J*aScript中在Map循环中检测并处理空数组元素  必由学官方登录入口 必由学教师学生账号快速访问  Composer的 archive 命令怎么用_快速打包你的PHP项目及其Composer依赖  LINUX下如何进行磁盘分区_fdisk与parted工具在LINUX中的使用对比  PHP文件上传至S3:策略、考量与避免本地存储的挑战  Python大型XML文件高效流式解析教程  天眼查企业查询官网入口 天眼查官方网页版查询  汽水音乐在线解析 汽水音乐在线解析入口  sublime怎么格式化代码_sublime代码美化与一键排版插件配置  Golang如何使用net/url解析URL_Golang URL解析与处理方法  Node.js CSV 数据处理:基于字段空值条件过滤整条记录的策略  漫蛙manwa官网登录界面_漫蛙漫画网页版主站入口  Go语言中高效处理x-www-form-urlencoded表单数据  在J*a中如何使用BigDecimal进行高精度计算_BigDecimal类应用指南  腾讯视频怎么举报不良内容_腾讯视频内容举报流程与违规信息处理方法  Tailwind CSS line-clamp 布局问题解析与修复指南  在J*a中如何使用ForkJoinPool进行分治任务并行处理_ForkJoinPool分治并行技巧说明  Odoo 16:在表单视图中基于当前记录动态修改Tree视图属性  j*a toString()的覆盖  Yandex搜索引擎官网入口_俄罗斯Yandex免登录一键直达  漫蛙2正版漫画站 漫蛙2网页版快速访问入口  PHP教程:高效从URL路径中提取倒数第二个片段  PHP面向对象编程中避免重复创建PDO数据库连接的最佳实践  b站如何看历史记录_b站观看历史找回方法  铁路12306卧铺选择攻略 铁路12306下铺座位预定技巧  J*aScript类型检查_j*ascript代码规范  移动端XML文件怎么转换成Excel 手机和平板上的解决方案  Typer应用中动态命令行参数的解析与处理  HuggingFaceEmbeddings中向量嵌入维度调整的限制与理解  优化Log4j2控制台输出性能:解决异步日志瓶颈  《主播少女的秘密账号迷宫》首支宣传片  sublime怎么预览Markdown渲染效果_Markdown Preview插件 for sublime教程  c++如何实现单例设计模式_c++线程安全的单例模式写法  Win11怎么开启高性能模式_Windows 11电源计划优化设置  Python复杂任务中断策略:通过回调函数实现优雅停止  德邦快递查询平台 德邦快递物流信息查询入口  C++如何生成随机数_C++ random库使用方法与范围设置  Go语言:非阻塞式判断标准输入(os.Stdin)是否有数据  黑鲨3Pro怎样在相册开漫画风滤镜_iPhone黑鲨3Pro相册开漫画风滤镜【趣味滤镜】  在Go Martini框架中高效服务动态生成图像的实践指南  excel怎么制作工资条 excel快速生成工资条的方法  解决Django多数据库/多Schema环境下外键迁移问题  Excel如何用迷你图显趋势_Excel用迷你图显趋势【趋势小图】  Windows10怎么开启存储感知 Windows10系统设置自动清理临时文件释放C盘空间【教程】  哔哩哔哩忘记密码了怎么找回_哔哩哔哩密码找回方法  Basecamp怎样用留言钉固定重点_Basecamp用留言钉固定重点【重点标记】  Win10如何清理注册表垃圾 Win10手动清理无效注册表【技巧】  ExcelARRAYTOTEXT函数怎么自定义分隔符输出数组文本_ARRAYTOTEXT实现动态生成SQL语句 

在线客服
服务热线

服务热线

4008988990

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!