什么是信号和槽?纯C++中如何实现信号和槽?

什么是信号和槽?

在Qt框架中,信号和槽是一种非常灵活的机制,用于在对象之间进行通信。信号和槽可以将两个对象解耦并连接起来,从而使得一个对象发生变化时,另一个对象就能够接收到相应的通知,并执行相关的操作。

例如,在编写一个GUI程序时,我们可以将一个按钮的点击事件定义为一个信号,然后将该信号连接到一个函数,这个函数就成了一个槽函数。当用户点击按钮时,信号就会被触发,从而导致与之连接的槽函数被调用。

纯C++中如何实现信号和槽?

虽然Qt框架中提供了元对象系统等技术来支持信号和槽的实现,但是我们也可以使用纯C++代码来实现信号和槽的机制。下面,我们以一个示例代码来说明纯C++中如何实现信号和槽。

#pragma once
// 槽
class Slot
{
public:
    virtual void execute() = 0;  // 执行槽函数
};
#pragma once
#include "Slot.h"
// 带参数的槽
template <typename T>
class SlotWithData : public Slot
{
public:
    using CallbackType = void (*)(T);

    SlotWithData(CallbackType callback) : m_callback(callback) {}

    void execute() override {}

    void execute(T data)
    {
        m_callback(data);
    }

private:
    CallbackType m_callback;
};
#pragma once
#include <list>
#include "Slot.h"
#include "SlotWithData.h"
// 信号
template <typename T>
class Signal
{
public:
    void connect(Slot* slot);  // 将槽连接到信号
    void disconnect(Slot* slot); // 解除槽与信号的绑定
    

    void emit(T data);  // 发送信号,并执行相关的槽函数

private:
    std::list<Slot*> slots;
};

template<typename T>
inline void Signal<T>::connect(Slot* slot)
{
    slots.push_back(slot);
}

template<typename T>
inline void Signal<T>::disconnect(Slot* slot)
{
    slots.remove(slot);
}

template<typename T>
inline void Signal<T>::emit(T data)
{
    for (auto slot : slots)
    {
        dynamic_cast<SlotWithData<T>*>(slot)->execute(data);
    }
}
#include <iostream>
#include <string>
#include <vector>
#include"Slot.h"
#include "Signal.h"
#include "SlotWithData.h"
using namespace std;


// 槽函数1
void slotFunc1(int data)
{
    cout << "slot1: " << data << endl;
}

// 槽函数2
void slotFunc2(string data)
{
    cout << "slot2: " << data << endl;
}

// 槽函数3
void slotFunc3(int data)
{
    cout << "slot3: " << data << endl;
}
// 槽函数4
void slotFunc4(int data)
{
    cout << "slot4: " << data << endl;
}
// 槽函数5
void slotFunc5(int data)
{
    cout << "slot5: " << data << endl;
}
int main()
{
    Signal<int> signal1;  // 整型信号
    Signal<string> signal2;  // 字符串信号
    int in=0;
    Slot* slot1 = new SlotWithData<int>(&slotFunc1);  // 将槽与函数绑定
    Slot* slot2 = new SlotWithData<string>(&slotFunc2);
    Slot* slot3 = new SlotWithData<int>(&slotFunc3);  // 将槽与函数绑定
    Slot* slot4 = new SlotWithData<int>(&slotFunc4);  // 将槽与函数绑定
    Slot* slot5 = new SlotWithData<int>(&slotFunc5);  // 将槽与函数绑定
    signal1.connect(slot1);  // 将槽连接到信号
    signal2.connect(slot2);
    signal1.connect(slot3);  // 将槽连接到信号
    signal1.connect(slot4);  // 将槽连接到信号
    signal1.connect(slot5);  // 将槽连接到信号
    while (true)
    {
        cin >> in;
        switch (in)
        {
        case 1:
            signal1.emit(in);  // 发送信号,并执行相关的槽函数
            break;
        case 2:
            signal2.emit(std::to_string(in));
            break;
        default:
            break;
        }
        
       
    }

    signal1.disconnect(slot1);
    signal2.disconnect(slot2);
    signal1.disconnect(slot3);
    signal1.disconnect(slot4);
    signal1.disconnect(slot5);
    delete slot1;
    delete slot2;
    delete slot3;
    delete slot4;
    delete slot5;
    return 0;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

在这个示例代码中,定义了一个名为Signal的模板类,它包含了connect、disconnect和emit三个函数。其中connect函数用于将槽与信号绑定在一起,disconnect函数用于解除该绑定关系,emit函数用于发送信号并执行对应的槽函数。

实现connect和disconnect函数时,我们使用std::list来存储槽函数。由于链表本身是按照添加顺序存储的,因此我们就能够支持一个信号对应多个槽函数的情况了。

在SlotWithData类中,我们定义了一个回调函数指针CallbackType,以及execute函数用于执行槽函数。当执行execute函数时,我们调用回调函数指针,并传递对应的参数data,从而实现信号和槽之间的数据交换。

在程序的主函数中,我们定义了两个信号signal1和signal2,分别对应整型和字符串类型。然后我们将两个槽函数slotFunc1和slotFunc2与这两个信号绑定起来。当使用emit函数发送信号时,与之连接的所有槽函数就会被执行。

最后,我们还添加了disconnect函数用于解除信号与槽的绑定,确保我们可以方便地添加、移除槽函数以及通知信号触发相应的槽函数。

总结

通过这篇博客的介绍,我们了解了如何在纯C++代码中实现信号和槽机制。尽管Qt框架提供了更加灵活和完善的支持,但是通过自己手动实现信号和槽机制,可以帮助我们更好地理解其底层机制,并且在开发一些嵌入式系统等环境下,也能够帮助我们实现基础的信号和槽功能。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值