概述

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. js获取时间搓

    var oData=new Date().getTime(2016-01-16); console.log(oData);

  2. cocos2d-x3.2下获取文件夹下所有文件名的方法

    这里提供一个函数获取文件夹下所有文件名的方法,直接上代码了. 原文地址:http://blog.csdn.net/qqmcy/article/details/36184733 // //  Visib ...

  3. 3.VS2010C++相关文件说明

    stdafx.h说明:stdafx的英文全称为:Standard Application Framework Extensions(标准应用程序框架的扩展).所谓头文件预编译,就是把一个工程(Proj ...

  4. OperateParticleWithCodes

    [OperateParticleWithCodes] Listing 6-6 shows how you might configure an emitter’s scale property. Th ...

  5. JavaIO(06)文件复制

    文件复制一般是采用两种方式进行操作: 1:将源文件中的内容全部读取到内存中,并一次性的写入到目标文件中:(不常用这种方式) 2:不将源文件中的内容全部读取进来,而是采用边读边写的方式:   实例01: ...

  6. G450 CPU 升级

    T系列是正常功耗的CPU,功耗35W,发热量大些, P系列是低功耗的U,功耗25W,发热量小些. P8700的性能比T6600高15%左右,不过平常应用感觉不是很明显. p8800cpu P8600 ...

  7. visualC/C++连接MySql数据库

    vs连接数据库其实就是将mysql数据库.h头文件接口.lib链接文件和dll执行文件加入到项目中.下面是配置如何加入. 转于http://www.cnblogs.com/justinzhang/ar ...

  8. Codeforces 682 D. Alyona and Strings (dp)

    题目链接:http://codeforces.com/contest/682/problem/D 给你两个字符串,求两个字符串中顺序k个的相同子串 长度之和.(注意是子串) dp[i][j][k][0 ...

  9. Spring+jpa+access

    ========访问数据库的属于文件============ driver=com.hxtt.sql.access.AccessDriverurl=jdbc:access:/D:/eclipse/pr ...

  10. 递归模式学习(recursion)

    所谓递归,就是方法调用自身.对于递归模式来说,要有一个出口来让递归结束,避免出现死循环. 实例全排列: 从n中拿出m个元素进行排列,当n==m时为全排列. 利用递归就是:把n个元素轮流放入第一个位置, ...