c++实现Qt信号槽机制

  • 信号槽机制的原理
    信号槽是观察者模式的一种实现,或者说是一种升华:
  • 一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知;
  • 一个槽就是一个观察者,通常就是在被观察的对象发生改变的时候——也可以说是信号发出的时候——被调用的函数;
  • 你可以将信号和槽连接起来,形成一种观察者-被观察者的关系;
  • 当事件或者状态发生改变的时候,信号就会被发出;同时,信号发出者有义务调用所有注册的对这个事件(信号)感兴趣的函数(槽);
  • 信号和槽是多对多的关系,一个信号可以连接多个槽,而一个槽也可以监听多个信号;

信号槽机制是Qt的一大特性,Qt信号与槽机制降低了Qt对象的耦合度。但这种做法效率低,不灵活。

  1. 使用c++实现简单的信号槽机制
    (1)信号模板类实现:
// CSignal.hpp
#ifndef _CSIGNAL_H
#define _CSIGNAL_H

#include <vector>
#include <memory>
#include <functional>
#include "CSlot.hpp"

#define emit
#define slots
#define signals public
#define connect(sender, signal, slot) ((sender)->signal.bind(slot))

template<typename... Args>
class Signal
{
public:
    using SlotPtr = std::shared_ptr<Slot<Args&&...>>; 
    using OnFunc = std::function<void(Args&&...)>;

    void bind(const OnFunc& func)
    {
        m_slotVec.push_back(SlotPtr(new Slot<Args&&...>(func)));
    }

    void operator()(Args&&... args)
    {
        for (auto& iter : m_slotVec)
        {
            iter->exec(std::forward<Args>(args)...);
        }
    }

private:
    std::vector<SlotPtr> m_slotVec;
};

#endif

(2)槽模板类实现

// CSlot.hpp
#ifndef _CSLOT_H
#define _CSLOT_H

#include <vector>
#include <functional>

template<typename... Args>
class Slot
{
public:
    using OnFunc = std::function<void(Args&&...)>;

    Slot(const OnFunc& func)
        : m_func(func)
    {
        // Do nothing
    }

    void exec(Args&&... args)
    {
        m_func(std::forward<Args>(args)...);
    }

private:
    OnFunc m_func = nullptr;
};

#endif

(3)具体信号执行类

#ifndef _SIGNAL_EXECUTER_H
#define _SIGNAL_EXECUTER_H

#include <iostream>
#include "CSignal.hpp"

class SignalExecutor
{
public:
    void start()
    {
        emit signal_print();
        emit signal_print_string("emit signal: signal_print_string!");
        emit signal_print_strings(100, "emit signal: signal_print_string!");
    }

signals:
    // 不带参数的信号
    Signal<> signal_print;  
    // 带参数的信号
    Signal<std::string> signal_print_string;
    // 带两个参数的信号
    Signal<int, std::string> signal_print_strings;
};

# endif //_SIGNAL_EXECUTER_H

(4)槽函数具体实现类

#ifndef _SLOT_EXECUTER_H
#define _SLOT_EXECUTER_H

#include <iostream>
#include "CSignal.hpp"


class SlotExecutor
{
public slots:
    void slot_print()
    {
        std::cout << "slot_print:" << std::endl;
    }

    void slot_print_string(const std::string& str)
    {
        std::cout << "slot_print_string:" << str << std::endl;
    }

    void slot_print_strings(int n, const std::string& str)
    {
        std::cout << "slot_print_strings, param 1:" << n << "======" 
        << "param 2:" << str << std::endl;
    }
};

# endif  //_SLOT_EXECUTER_H

(5)信号槽连接具体实现

#include <iostream>
#include "CSignal.hpp"
#include "slot_executer.h"
#include "signal_executer.h"

void print_string_public(const std::string& str)
{
    std::cout << "slot print_string_public:" << str << std::endl;
}


int main(int argc, char *argv[])
{
	SignalExecutor signal_executer;
    SlotExecutor slot_executer;

    // 无参数信号与无参数槽绑定
    connect(&signal_executer, signal_print
        , std::bind(&SlotExecutor::slot_print, &slot_executer));

    // 单参数信号与单参数槽绑定
    connect(&signal_executer, signal_print_string
        , std::bind(&SlotExecutor::slot_print_string
            , &slot_executer, std::placeholders::_1));

    // 两个参数信号与两个参数槽绑定
    connect(&signal_executer, signal_print_strings
        , std::bind(&SlotExecutor::slot_print_strings
            , &slot_executer, std::placeholders::_1, std::placeholders::_2));

    // 单参数信号与全局函数绑定
    connect(&signal_executer, signal_print_string
        , std::bind(print_string_public, std::placeholders::_1));

    // 单参数信号与lambda绑定
    connect(&signal_executer, signal_print_string
        , [](const std::string& str){
                std::cout << "lambda str: " << str << std::endl;
            });

    signal_executer.start();

    std::cout << "signal slot demo finish!" << std::endl;
	system("pause");
}
  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值