详解c++实现信号槽

目录
  • 用c++实现信号槽机制(signal-slot)
  • 总结

用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";
}
 

总结

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

(0)

相关推荐

  • c++ Qt信号槽原理

    1.说明 使用Qt已经好几年了,一直以为自己懂Qt,熟悉Qt,使用起来很是熟练,无论什么项目,都喜欢用Qt编写.但真正去看Qt的源码,去理解Qt的思想也就近两年的事. 本次就着重介绍一下Qt的核心功能--信号槽机制,相信接触过Qt的人都能很熟悉地使用,甚至,大部分人还能轻松地说出信息槽的几种用法.但是信号槽的核心可不是简单说说就能说清楚的. 那么,本次,就从Qt的源码中讲解一下信号槽的机制. 其实,直到写这篇文章,我也没有完全看明白相关的源码,只是明白了其中的大部分以及使用机制,其中还有很多细节

  • 详细分析C++ 信号处理

    信号是由操作系统传给进程的中断,会提早终止一个程序.在 UNIX.LINUX.Mac OS X 或 Windows 系统上,可以通过按 Ctrl+C 产生中断. 有些信号不能被程序捕获,但是下表所列信号可以在程序中捕获,并可以基于信号采取适当的动作.这些信号是定义在 C++ 头文件 <csignal> 中. 信号 描述 SIGABRT 程序的异常终止,如调用 abort. SIGFPE 错误的算术运算,比如除以零或导致溢出的操作. SIGILL 检测非法指令. SIGINT 程序终止(inte

  • 深入理解Qt信号槽机制

    目录 1. 信号和槽概述 1.1 信号的本质 1.2 槽的本质 1.3 信号和槽的关系 1. 信号和槽概述 信号槽是 Qt 框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式(发布-订阅模式).当某个`事件`发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal).这种发出是没有目的的,类似广播.如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号.也就是说,当信号发出时,被连

  • 详解c++实现信号槽

    目录 用c++实现信号槽机制(signal-slot) 总结 用c++实现信号槽机制(signal-slot) 信号槽机制的个人理解:信号槽是在两个c++类对象之间建立联系的通道,其中一个对象可称之为信号发送者(sender),另一个对象可称之为信号接收者(recver),sender通过信号槽发出信号后,recver就可以执行函数进行某些操作.也就是说应用程序通过信号槽可以在两个互不相关的对象之间建立起逻辑关系,使程序开发变得简洁.方便. 信号槽本质是由c++定义的类组成,分为两个部分:槽类和

  • Linux下的信号详解及捕捉信号

    信号的基本概念 每个信号都有一个编号和一个宏定义名称 ,这些宏定义可以在 signal.h 中找到. 使用kill -l命令查看系统中定义的信号列表: 1-31是普通信号: 34-64是实时信号 所有的信号都由操作系统来发! 对信号的三种处理方式 1.忽略此信号:大多数信号都可使用这种方式进行处理,但有两种信号却决不能被忽略.它们是:SIGKILL和SIGSTOP.这两种信号不能被忽略的,原因是:它们向超级用户提供一种使进程终止或停止的可靠方法.另外,如果忽略某些由硬件异常产生的信号(例如非法存

  • python GUI库图形界面开发之PyQt5信号与槽的高级使用技巧(自定义信号与槽)详解与实例

    PyQt5信号与槽高级自定义信号与槽 所谓高级自定义信号与槽,指的就是我们可以以自己喜欢的方式定义信号与槽函数,并传递参数,自定义信号的一般流程如下 定义信号 定义槽函数 连接信号与槽函数 发射信号 1.定义信号 通过类成员变量定义信号对象 #无参数的信号 signal1=pyqtSignal() #带一个参数(整数)的信号 signal2=pyqtSignal(int) #带两个参数(整数,字符串)的信号 signal3=pyqtSignal(int,str) #带一个参数(列表)的信号 si

  • 详解PyQt5信号与槽的几种高级玩法

    信号(Signal)和槽(Slot)是Qt中的核心机制,也是在PyQt编程中对象之间进行通信的机制.本文介绍了几种PyQt 5信号与槽的几级玩法. 在Qt中,每一个QObject对象和PyQt中所有继承自QWidget的控件(这些都是QObject的子对象)都支持信号与槽机制.当信号发射时,连接的槽函数将会自动执行.在PyQt 5中信号与槽通过object.signal.connect()方法连接. PyQt的窗口控件类中有很多内置信号,开发者也可以添加自定义信号.信号与槽具有如下特点. 一个信

  • PyQt5信号与槽机制案例详解

    信号和槽机制是 QT 的核心机制,要精通 QT 编程就必须对信号和槽有所了解.信号和槽是一种高级接口,应用于对象之间的通信,它是 QT 的核心特性,也是 QT 区别于其它工具包的重要地方. 信号和槽是用来在对象间传递数据的方法:当一个特定事件发生的时候,信号会被发射出来,槽调用是用来响应相应的信号的.Qt中对象已经包含了许多预定义的信号(基本组件都有各自特有的预定义的信号),根据使用的场景也可以添加新的信号.同样Qt的对象中已经包含了许多预定义的槽函数,但也可以根据使用的场景添加新的槽函数. 一

  • PyQt5通信机制 信号与槽详解

     前言 信号和槽是PyQt编程对象之间进行通信的机制.每个继承自QWideget的控件都支持信号与槽机制.信号发射时(发送请求),连接的槽函数就会自动执行(针对请求进行处理).本文主要讲述信号和槽最基本.最经常使用方法.就是内置信号和槽的使用的使用方法. 内置信号和槽 所谓内置信号与槽的使用.是指在发射信号时,使用窗口控件的函数,而不是自定义的函数.信号与槽的连接方法是通过QObject.signal.connect将一个QObject的信号连接到另一个QObject的槽函数. 在任何GUI设计

  • Python 基于FIR实现Hilbert滤波器求信号包络详解

    在通信领域,可以通过希尔伯特变换求解解析信号,进而求解窄带信号的包络. 实现希尔伯特变换有两种方法,一种是对信号做FFT,单后只保留单边频谱,在做IFFT,我们称之为频域方法:另一种是基于FIR根据传递函数设计一个希尔伯特滤波器,我们称之为时域方法. # -*- coding:utf8 -*- # @TIME : 2019/4/11 18:30 # @Author : SuHao # @File : hilberfilter.py import scipy.signal as signal im

  • 基于Django signals 信号作用及用法详解

    1.Model signals django.db.models.signales 作用于django的model操作上的一系列信号 1)pre_init() django.db.models.signals.pre_init 当模型实例化时调用,在__init__()之前执行 三个参数: pre_init(sender, args, kwargs): sender:创建实例的模型类 args:参数列表 kwargs:通过字典形式传递的参数 2)post_init() django.db.mod

  • Python的信号库Blinker用法详解

    作为一个信号库,使用时候是支持一对一以及一对多的订阅模式,可以实现发送数据等,一般情况下,只要能够使用到Blinker的,一般都是应用在技术设计以及垃圾回收上等等,以上就是关于Blinker库的基本信息,具体的情况,小编将详细的为大家介绍讲解,好啦一起来了解看下吧. 安装环境: Python 3.6.4 安装方式: pip install blinker 使用实例: In [1]: from blinker import signal In [2]: a = signal('signal_tes

  • Java详解多线程协作作业之信号同步

    目录 一.信号同步 二.基于时间维度 1.CountDownLatch 2.CyclicBarrier 三.基于信号维度 一.信号同步 多线程很多时候是协作作业.比如4个线程对电商数据分季度统计,统计完成之后,再汇总.如何知道4个线程都执行完成呢,我们可以使用JDK1.5给我们提供的辅助类CountDownLatch( 减少计数).CyclicBarrier(循环栅栏).Semaphore(信号灯). 二.基于时间维度 1.CountDownLatch 多少个协作线程就初始化CountDownL

随机推荐