概述

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

C++11实现Qt的信号槽机制的更多相关文章

  1. 非Qt工程使用Qt的信号槽机制

    非Qt工程,使用Qt的信号槽机制,蛋疼不?反正我现在就是要做这样一件蛋疼的事. 要使用Qt的信号槽机制,下面是从Qt Assist里面关于 signal & slots 的一句介绍: All ...

  2. VJGUI消息设计-兼谈MFC、QT和信号/槽机制

    星期六下午4点,还在公司加班.终于写完了下周要交工的一个程序. 郁闷,今天这几个小时写了有上千行代码吧?虽然大部分都是Ctrl-C+Ctrl-V,但还是郁闷. 作为一个有10年经验的MFC程序员,郁闷 ...

  3. Qt学习记录--02 Qt的信号槽机制介绍(含Qt5与Qt4的差异对比)

    一 闲谈: 熟悉Window下编程的小伙伴们,对其消息机制并不陌生, 话说:一切皆消息.它可以很方便实现不同窗体之间的通信,然而MFC库将很多底层的消息都屏蔽了,尽管使用户更加方便.简易地处理消息,但 ...

  4. QT信号槽机制

    信号槽 信号槽是QT中用于对象间通信的一种机制,也是QT的核心机制.在GUI编程中,我们经常需要在改变一个组件的同时,通知另一个组件做出响应.例如: 一开始我们的Find按钮是未激活的,用户输入要查找 ...

  5. QT写hello world 以及信号槽机制

    QT是一个C++的库,不仅仅有GUI的库.首先写一个hello world吧.敲代码,从hello world 写起. #include<QtGui/QApplication> #incl ...

  6. 使用 C++11 编写类似 QT 的信号槽——上篇

    了解 QT 的应该知道,QT 有一个信号槽 Singla-Slot 这样的东西.信号槽是 QT 的核心机制,用来替代函数指针,将不相关的对象绑定在一起,实现对象间的通信. 考虑为 Simple2D 添 ...

  7. Qt开发之信号槽机制

    一.信号槽机制原理 1.如何声明信号槽 Qt头文件中一段的简化版: class Example: public QObject { Q_OBJECT signals: void customSigna ...

  8. QT源码之Qt信号槽机制与事件机制的联系

    QT源码之Qt信号槽机制与事件机制的联系是本文要介绍的内容,通过解决一个问题,从中分析出的理论,先来看内容. 本文就是来解决一个问题,就是当signal和slot的连接为Qt::QueuedConne ...

  9. QT学习记录之理解信号槽机制

    作者:朱金灿 来源:http://blog.csdn.net/clever101 QT的事件机制采用的信号槽机制.所谓信号槽机制,简而言之就是将信号和信号处理函数绑定在一起,比如一个按钮被单击是一个信 ...

随机推荐

  1. dom 关键字提示

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  2. SQL Server常用元数据函数

    元数据函数 1.获取数据库标识符DB_ID DB_ID函数用于获取当前数据库的唯一ID(int数据类型),数据库ID用于服务器上唯一区分书库. 语法结构: DB_ID (['database_name ...

  3. JavaScript 变量、作用域及内存详解

    基本类型值有:undefined,NUll,Boolean,Number和String,这些类型分别在内存中占有固定的大小空间,他们的值保存在栈空间,我们通过按值来访问的. (1)值类型:数值.布尔值 ...

  4. 转】MyEclipse使用总结——MyEclipse中配置WebLogic12c服务器

    原博文出自于:http://www.cnblogs.com/xdp-gacl/p/4142495.html 感谢! MyEclipse中配置WebLogic12c服务器的步骤如下: [Window]→ ...

  5. C#完整的通信代码(点对点,点对多,同步,异步,UDP,TCP)

    C# code namespace UDPServer { class Program { static void Main(string[] args) { int recv; byte[] dat ...

  6. XSLT模糊查询函数contains不区分大小写,for-each排序

    代码如下: <xsl:for-each select="//NewDataSet/map/area[contains(translate(@alt, 'ABCDEFGHIJKLMNOP ...

  7. C# List 中 Find 方法

    实例化一个集合 List<User> userCollection = new List<User>(); userCollection.Add(new User(1, &qu ...

  8. js时间转换相关

    1.json时间格式转换 function ChangeDateFormat(jsondate) { if (!jsondate||jsondate.length < 1) {return &q ...

  9. Gson 和 Fastjson 你不知道的事

    背景 目前在公司负责的业务, 主要是跟JSON数据打交道, fastjson .gson都用, 他们适用于不同场景.fastjson号称是业界处理json效率最高的框架, 没有之一.但在某些场景下, ...

  10. 用jquery判断当前显示器的分辨率,加载不同CSS

    <link rel="stylesheet" type="text/css" id="css"><script langu ...