我的编程空间,编程开发者的网络收藏夹
学习永远不晚

详解c++实现信号槽

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

详解c++实现信号槽

用c++实现信号槽机制(signal-slot)

信号槽机制的个人理解:信号槽是在两个c++类对象之间建立联系的通道,其中一个对象可称之为信号发送者(sender),另一个对象可称之为信号接收者(recver),sender通过信号槽发出信号后,recver就可以执行函数进行某些操作。也就是说应用程序通过信号槽可以在两个互不相关的对象之间建立起逻辑关系,使程序开发变得简洁、方便。

信号槽本质是由c++定义的类组成,分为两个部分:槽类和信号类

槽类(slot):可理解为插槽,其内部有两个私有成员,存储待执行的类对象和对象中的方法指针,可理解将信号接收者(recver)插入了插槽中。槽的另一端连接信号,通过在信号(signal)类的实例中存储槽(slot)指针的方式实现,若在signal对象中插入多个slot,则代表一个信号与多个recver建立了联系,当信号来临时,可以根据slot的插入先后顺序轮流执行事件方法。

信号类(signal):其内部有一个容器,存储连接到信号类实例的槽类指针,同时提供一个执行方法,当方法调用时,在方法内部调用所存储的槽类指针所指向的槽内部保存的recver的方法。

若要使用信号槽,则信号发送者(sender)类需要在内部包含信号类(signal)实例,同时包含一个方法来调用signal上的执行方法。该方法称之为发出信号。

综上,作为sender的任意object类包含有signal成员,通过func发出信号,func内部调用object.signal上的执行方法,此处通过重载()实现,执行方法内部是循环调用保存在signal中的slot指针列表,而slot指针指向的slot实例中存储有recver和recver.func,通过slot的exec方法则可以执行func,这就实现了一个触发信号的完整流程。

为了实现任意sender和任意recver关联,slot和signal类并不知道要关联对象以及执行方法的具体类型和参数类型,因此要使用泛型编程

代码及说明如下(整理借鉴自csdn):


/// <summary>
/// 先实现槽基类,包含两个虚函数对象,主要为后续调用提供接口
/// 子类负责实现exec方法
/// </summary>
/// <typeparam name="TParam">Recver中待执行函数的参数类型</typeparam>
template <class TParam>
class SlotBase
{
public:
    virtual void Exec(TParam param) = 0;
    virtual ~SlotBase() {};
};
/// <summary>
/// Slot子类,负责实现exec方法,通过exec调用recver.func,同时Slot构造函数负责初始化两个内部变量,将需要关联的recver和recver.func插入槽
/// </summary>
/// <typeparam name="TRecver">recver类的具体类型</typeparam>
/// <typeparam name="TParam">recver.func的参数类型</typeparam>
template <class TRecver,class TParam>
class Slot:public SlotBase<TParam>
{
public:
    Slot(TRecver* pObj, void (TRecver::* func)(TParam)) 
    {
        m_pRecver = pObj;
        m_func = func;
    };
    VOID Exec(TParam param)
    {
        (m_pRecver->*m_func)(param);
    };
private:
    TRecver* m_pRecver = NULL;
    void (TRecver::* m_func)(TParam);
};
/// <summary>
/// 信号类
/// 私有成员m_pSlotSet,存储槽指针的vector
/// 重载(),在括号调用参数时,循环调用m_pSlotSet中存储的槽指针,将参数传递给槽的exec方法
/// bind():将一个槽与信号类实例关联起来
/// 
/// </summary>
/// <typeparam name="TParam">待执行方法的参数类型</typeparam>
/// <typeparam name="TRecver">recver类的类型</typeparam>
template<class TParam>
class Signal
{
public:
    template<class TRecver>
    void Bind(TRecver* pObj, void (TRecver::* func)(TParam))
    {
        m_pSlotSet.push_back(new Slot<TRecver,TParam>(pObj, func));
    };
    void operator()(TParam param)
    {
        for(int i=0;i<m_pSlotSet.size();i++)
        {
            m_pSlotSet[i]->Exec(param);
        }
    };
    ~Signal() 
    {
        for (int i = 0; i < m_pSlotSet.size(); i++)
            delete m_pSlotSet[i];
    };
private:
    std::vector<SlotBase<TParam>*> m_pSlotSet;
};
//开始模拟
class RecverOne
{
public:
    void functionOne(int param) 
    {
        std::cout << "这是接收者1中的某个方法执行:" << param << std::endl;
    };
};
class RecverTwo
{
public:
    void functionTwo(int param)
    {
        std::cout << "这是接收者2中的某个方法执行:" << param << std::endl;
    };
};
class SenderObj
{
public:
    //模拟值改变发出信号
    void testSginal(int param) 
    {
        valueChanged(param);
    };
public:
    Signal<int> valueChanged;//定义一个当值改变时触发的信号
};
//为了更方便地将sender中的signal与槽和recver关联,可以定义一个宏
#define connect(sender,signal,recver,method) ((sender)->signal.Bind(recver,method))
int main()
{
    //开始测试
    //先定义两个接收者
    RecverOne* R1 = new RecverOne;
    RecverTwo* R2 = new RecverTwo;
    //定义一个发送者
    SenderObj* sd = new SenderObj;
    //将R1和R2中的函数插入sd中的信号槽
    connect(sd, valueChanged, R1, &RecverOne::functionOne);
    connect(sd, valueChanged, R2, &RecverTwo::functionTwo);
    //发送信号
    sd->valueChanged(5);
    std::cout << "Hello World!\n";
}
 

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

详解c++实现信号槽

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C++Boost.Signals2信号/槽概念

Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
2022-12-08

Qt开发如何实现跨窗口信号槽通信

这篇文章主要介绍“Qt开发如何实现跨窗口信号槽通信”,在日常操作中,相信很多人在Qt开发如何实现跨窗口信号槽通信问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Qt开发如何实现跨窗口信号槽通信”的疑惑有所帮助!
2023-06-22

C++使用标准库实现事件和委托以及信号和槽机制

这篇文章主要为大家详细介绍了C++如何使用标准库实现事件和委托以及信号和槽机制,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
2022-11-13

如何进行Qt 信号自定义槽函数的实现

本篇文章为大家展示了如何进行Qt 信号自定义槽函数的实现,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Qt中实现自定义信号与槽函数,信号用于发送并触发槽函数,槽函数则是具体的功能实现,如下我们以老师
2023-06-21

qt信号槽连接connect无响应如何解决

当 `connect` 函数无响应时,可能是由于以下几个原因造成的:1. 信号和槽的参数不匹配:确保信号和槽的参数类型和数量匹配。如果不匹配,`connect` 函数将无法连接信号和槽。2. 信号和槽的签名不匹配:确保信号和槽的参数和返回类
2023-09-27

C#联合VisionPro实现TCP/IP通信详解

这篇教程详细介绍了使用C#和CognexVisionPro库实现TCP/IP通信。它涵盖了库设置、TCP/IP服务器和客户端的创建、数据发送和接收,以及事件处理。还提供了处理服务器连接事件的代码示例。本教程旨在帮助读者建立可靠的计算机之间通信。
C#联合VisionPro实现TCP/IP通信详解
2024-04-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录