我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++Boost.Signals2信号/槽概念

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C++Boost.Signals2信号/槽概念

一、关于Boost.Signals2

Boost.Signals2 实现了信号/槽的概念。一个或多个函数(称为槽)与可以发出信号的对象相关联。每次发出信号时,都会调用链接的函数。

信号/槽概念在开发具有图形用户界面的应用程序时非常有用。可以对按钮进行建模,以便在用户单击它们时发出信号。它们可以支持指向许多函数的链接以处理用户输入。这样就可以灵活地处理事件。

std::function 也可用于事件处理。 std::function 和 Boost.Signals2 之间的一个重要区别是 Boost.Signals2 可以将多个事件处理程序与单个事件相关联。因此,Boost.Signals2更适合支持事件驱动开发,应该是任何需要处理事件的首选。

Boost.Signals2 继承了库 Boost.Signals,后者已被弃用且本书未讨论。

Table of Contents

Signals

Connections

Multithreading

二、关于Signals库

Boost.Signals2 提供类 boost::signals2::signal,可用于创建信号。此类在 boost/signals2/signal.hpp 中定义。或者,您可以使用头文件 boost/signals2.hpp,这是一个主头文件,定义了 Boost.Signals2 中可用的所有类和函数。

Boost.Signals2 定义了 boost::signals2::signal 和其他类,以及命名空间 boost::signals2 中的所有函数。

示例 67.1。 “你好世界!”使用 boost::signals2::signal

#include <boost/signals2.hpp>
#include <iostream>
using namespace boost::signals2;
int main()
{
  signal<void()> s;
  s.connect([]{ std::cout << "Hello, world!\n"; });
  s();
}

boost::signals2::signal 是一个类模板,它期望将用作事件处理程序的函数的签名作为模板参数。在示例 67.1 中,只有签名为 void() 的函数才能与信号相关联。

lambda 函数通过 connect() 与信号 s 相关联。因为 lambda 函数符合所需的签名 void(),所以关联已成功建立。每当触发信号 s 时,都会调用 lambda 函数。

信号是通过像调用常规函数一样调用 s 来触发的。此函数的签名与作为模板参数传递的签名匹配。括号是空的,因为 void() 不需要任何参数。调用 s 会产生一个触发器,而该触发器又会执行之前与 connect() 相关联的 lambda 函数。

示例 67.1 也可以使用 std::function 实现,如示例 67.2 所示。

示例 67.2。 “你好世界!”使用 std::function

#include <functional>
#include <iostream>
int main()
{
  std::function<void()> f;
  f = []{ std::cout << "Hello, world!\n"; };
  f();
}

在示例 67.2 中,调用 f 时也会执行 lambda 函数。虽然 std::function 只能用于类似示例 67.2 的场景,但 Boost.Signals2 提供了更多种类。例如,它可以将多个函数与特定信号相关联(参见示例 67.3)。

示例 67.3。带有 boost::signals2::signal 的多个事件处理程序

#include <boost/signals2.hpp>
#include <iostream>
using namespace boost::signals2;
int main()
{
  signal<void()> s;
  s.connect([]{ std::cout << "Hello"; });
  s.connect([]{ std::cout << ", world!\n"; });
  s();
}

boost::signals2::signal 允许您通过重复调用 connect() 将多个函数分配给特定信号。每当触发信号时,函数都会按照它们与 connect() 关联的顺序执行。

顺序也可以在 connect() 的重载版本的帮助下明确定义,它需要一个 int 类型的值作为附加参数(示例 67.4)。

示例 67.4。具有明确顺序的事件处理程序

#include <boost/signals2.hpp>
#include <iostream>
using namespace boost::signals2;
int main()
{
  signal<void()> s;
  s.connect(1, []{ std::cout << ", world!\n"; });
  s.connect(0, []{ std::cout << "Hello"; });
  s();
}

与前面的示例一样,示例 67.4 显示 Hello, world!。

要从信号中释放关联函数,请调用 disconnect()。

示例 67.5。断开事件处理程序与 boost::signals2::signal 的连接

#include <boost/signals2.hpp>
#include <iostream>
using namespace boost::signals2;
void hello() { std::cout << "Hello"; }
void world() { std::cout << ", world!\n"; }
int main()
{
  signal<void()> s;
  s.connect(hello);
  s.connect(world);
  s.disconnect(world);
  s();
}

Example 67.5 

示例 67.5 仅打印 Hello,因为与 world() 的关联在信号被触发之前已释放。

除了 connect() 和 disconnect() 之外,boost::signals2::signal 还提供了几个成员函数(参见示例 67.6)。

示例 67.6。 boost::signals2::signal 的附加成员函数

#include <boost/signals2.hpp>
#include <iostream>
using namespace boost::signals2;
int main()
{
  signal<void()> s;
  s.connect([]{ std::cout << "Hello"; });
  s.connect([]{ std::cout << ", world!"; });
  std::cout << s.num_slots() << '\n';
  if (!s.empty())
    s();
  s.disconnect_all_slots();
}

num_slots() 返回关联函数的数量。如果没有函数关联,num_slots() 返回 0。empty() 告诉您事件处理程序是否已连接。而 disconnect_all_slots() 的作用正如它的名字所说:它释放所有现有的关联。

示例 67.7。处理事件处理程序的返回值

#include <boost/signals2.hpp>
#include <iostream>
using namespace boost::signals2;
int main()
{
  signal<int()> s;
  s.connect([]{ return 1; });
  s.connect([]{ return 2; });
  std::cout << *s() << '\n';
}

在示例 67.7 中,两个 lambda 函数与信号关联。第一个 lambda 函数返回 1,第二个返回 2。

示例 67.7 将 2 写入标准输出。 s 正确接受了两个返回值,但除了最后一个之外的所有返回值都被忽略了。默认情况下,只返回所有关联函数的最后一个返回值。

请注意,s() 不会直接返回上次调用的函数的结果。返回类型为 boost::optional 的对象,取消引用时返回数字 2。触发与任何函数无关的信号不会产生任何返回值。因此,在这种情况下,boost::optional 允许 Boost.Signals2 返回一个空对象。 boost::optional 在第 21 章中介绍。

可以自定义信号,以便相应地处理各个返回值。为此,必须将组合器作为第二个模板参数传递给 boost::signals2::signal。

示例 67.8。使用用户定义的组合器查找最小返回值

#include <boost/signals2.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace boost::signals2;
template <typename T>
struct min_element
{
  typedef T result_type;
  template <typename InputIterator>
  T operator()(InputIterator first, InputIterator last) const
  {
    std::vector<T> v(first, last);
    return *std::min_element(v.begin(), v.end());
  }
};
int main()
{
  signal<int(), min_element<int>> s;
  s.connect([]{ return 1; });
  s.connect([]{ return 2; });
  std::cout << s() << '\n';
}

组合器是一个具有重载的 operator() 的类。该运算符使用两个迭代器自动调用,这两个迭代器用于访问与特定信号关联的函数。当迭代器被取消引用时,函数被调用并且它们的返回值在组合器中变得可用。然后可以使用标准库中的常用算法,例如 std::min_element() 来计算并返回最小值(参见示例 67.8)。

boost::signals2::signal 使用 boost::signals2::optional_last_value 作为默认组合器。此组合器返回 boost::optional 类型的对象。用户可以定义一个具有任何类型返回值的组合器。例如,示例 67.8 中的组合器 min_element 返回作为模板参数传递给 min_element 的类型。

无法将诸如 std::min_element() 之类的算法作为模板参数直接传递给 boost::signals2::signal。 boost::signals2::signal 期望组合器定义一个名为 result_type 的类型,它表示 operator() 返回值的类型。由于这个类型没有被标准算法定义,所以编译器会报错。

请注意,不可能将迭代器 first 和 last 直接传递给 std::min_element() ,因为该算法需要前向迭代器,而组合器使用输入迭代器。这就是为什么在使用 std::min_element() 确定最小值之前使用向量存储所有返回值的原因。

示例 67.9 修改组合器以将所有返回值存储在容器中,而不是评估它们。它将所有返回值存储在一个向量中,然后由 s() 返回该向量。

示例 67.9。使用用户定义的组合器接收所有返回值

#include <boost/signals2.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace boost::signals2;
template <typename T>
struct return_all
{
  typedef T result_type;
  template <typename InputIterator>
  T operator()(InputIterator first, InputIterator last) const
  {
    return T(first, last);
  }
};
int main()
{
  signal<int(), return_all<std::vector<int>>> s;
  s.connect([]{ return 1; });
  s.connect([]{ return 2; });
  std::vector<int> v = s();
  std::cout << *std::min_element(v.begin(), v.end()) << '\n';
}

练习

创建一个带有课程按钮的程序。该类应代表图形用户界面中的按钮。添加成员函数 add_handler() 和 remove_handler() ,它们都希望传递一个函数。如果调用另一个名为 click() 的成员函数,则应依次调用已注册的处理程序。通过注册一个将消息写入标准输出的处理程序来实例化按钮并测试该类。调用 click() 来模拟鼠标点击按钮。

到此这篇关于C++ Boost.Signals2信号/槽概念的文章就介绍到这了,更多相关C++ Boost Signals2内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++Boost.Signals2信号/槽概念

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C++Boost.Signals2信号/槽概念

Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
2022-12-08

C++使用标准库实现事件和委托以及信号和槽机制

这篇文章主要为大家详细介绍了C++如何使用标准库实现事件和委托以及信号和槽机制,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录