zoukankan      html  css  js  c++  java
  • C++11实现Qt的信号槽机制

    概述

    Qt的信号槽机制是Qt的核心机制,按钮点击的响应、线程间通信等都是通过信号槽来实现的,boost里也有信号槽,但和Qt提供的使用接口很不一样,本文主要是用C++11来实现一个简单的信号槽,该信号槽也实现了emit、slots、signals、connect关键字和函数、使用方法和Qt的信号槽基本类似,该信号槽机制用到了C++11的特性有:

    1. 可变参数模板类
    2. 智能指针
    3. 函数相关std::function、std::bind
    4. using关键字
    5. 完美转发std::forward

    该信号槽提供类成员函数、类非成员函数的连接、连接时支持std::bind、以及lambda表达式,信号槽机制的核心代码如下:

    // Connect.hpp
    #ifndef _CONNECT_H
    #define _CONNECT_H
    
    #include <vector>
    #include <memory>
    #include <functional>
    
    #define emit
    #define slots
    #define signals public
    #define connect(sender, signal, slot) ((sender)->signal.bind(slot))
    
    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;
    };
    
    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
    
    
    

    下面是使用C++11信号槽机制的代码:

    // main.cpp
    /************************************************
     * 该例程讲解用C++11来实现Qt的信号槽机制
     * 使用到的C++11特性有:
     * 1.可变参数模板类
     * 2.智能指针
     * 3.函数相关std::function、std::bind
     * 4.using关键字
     * 5.完美转发std::forward
    ************************************************/
    #include "Connect.hpp"
    #include <iostream>
    #include <string>
    
    class A
    {
    public:
        void start()
        {
            emit m_s1();
            emit m_s2("Hello C++11");
            emit m_s3(100, "Hello C++11");
        }
    
    signals:
        Signal<> m_s1;  // 不带参数的信号
        Signal<std::string> m_s2;
        Signal<int, std::string> m_s3;
    };
    
    class B
    {
    public slots:
        void func1()
        {
            std::cout << "func1" << std::endl;
        }
    
        void func2(const std::string& str)
        {
            std::cout << str << std::endl;
        }
    
        void func3(int n, const std::string& str)
        {
            std::cout << n << " " << str << std::endl;
        }
    };
    
    void func(const std::string& str)
    {
        std::cout << "func " << str << std::endl;
    }
    
    int main()
    {
        A a;
        B b;
    
        // 信号与槽绑定
        connect(&a, m_s1, std::bind(&B::func1, &b));
        connect(&a, m_s2, std::bind(&B::func2, &b, std::placeholders::_1));
        connect(&a, m_s3, std::bind(&B::func3, &b, std::placeholders::_1, std::placeholders::_2));
        connect(&a, m_s2, std::bind(func, std::placeholders::_1));
        connect(&a, m_s2, [](const std::string& str)
                {
                    std::cout << "lambda str: " << str << std::endl;
                });
    
        a.start();
    
        return 0;
    }
    
    
    

    TODO

    该例子只是实现了简单的信号槽机制,还有很多功能都没有实现

    1. 不支持断开信号与槽的连接disconnect
    2. 不支持AutoConnection、DirectConnection、QueuedConnection、UniqueConnection
    3. 不支持无锁连接
    4. etc...

    该例子的github地址:https://github.com/chxuan/samples/tree/master/Connect

  • 相关阅读:
    EasyUI Combobox组合框(模糊搜索、默认值绑定)
    Asp.Net下载文件时中途失败问题
    VS使用小技巧之——设置调试时启动项目和启动页
    VS使用小技巧之——给代码添加region
    VS使用小技巧之——引入整个文件夹
    VS使用小技巧之——任务列表
    FineUI给表格行内链接设置弹出窗体
    cnpm私服搭建和发布包
    阿里云产品术语和docker
    angularjs1.x的一些知识点整理
  • 原文地址:https://www.cnblogs.com/highway-9/p/5559558.html
Copyright © 2011-2022 走看看