热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C++中的可调用对象及其应用

本文介绍了C++中的可调用对象概念,包括函数指针、仿函数、类成员函数指针等,并详细探讨了`std::function`和`std::bind`在统一处理这些可调用对象时的作用和实现方法。
### 可调用对象

在 C++ 中,可调用对象是指可以像普通函数一样调用的对象。具体来说,可调用对象可以是以下几种形式之一:

1. **函数指针**:指向函数的指针。
2. **仿函数**:具有 `operator()` 成员函数的类对象。
3. **可转换为函数指针的类对象**:可以通过某种方式转换为函数指针的类对象。
4. **类成员函数指针**:指向类成员函数的指针。

下面是一些示例代码:

```cpp
void func() {
cout <<"func" <}

struct Foo {
void operator()() { cout <<"Foo::operator()" <};

struct Bar {
using fr_t = void(*)();
static void func() { cout <<"Bar::func" < operator fr_t() { return func; }
};

struct A {
int a_;
void mem_func() { cout <<"A::mem_func" <};

int main() {
void (*func_ptr)() = &func; // 1. 指向函数指针
func();
Foo foo;
foo(); // 2. 定义对象,重载()
Bar bar;
bar(); // 3. 调用重载,返回一个静态函数地址
void (A::*mem_func_ptr)() = &A::mem_func; // 函数指针指向A作用域下的mem_func函数地址
A aa;
(aa.*mem_func_ptr)(); // 调用类成员函数
return 0;
}
```

### 可调用对象包装器——std::function

`std::function` 是 C++11 引入的一个模板类,用于包装各种可调用对象。它可以容纳除类成员函数指针以外的所有可调用对象,并允许以统一的方式处理这些对象。

```cpp
void fun() {
cout <<__FUNCTION__ <}

class Foo {
public:
static int foo_func(int a) {
cout <<__FUNCTION__ <<"(" < return 0;
}
};

class Bar {
int val;
public:
Bar(int x = 0) : val(x) {}
int operator()(int a) const {
cout <<__FUNCTION__ <<"(" < return a;
}
};

int main() {
std::function fr1 = fun;
fr1();
std::function fr2 = Foo::foo_func;
fr2(10);
Bar bar(12);
Bar bac(23);
fr2 = bar;
fr2(12);
fr2 = bac;
fr2(34);
return 0;
}
```

### std::bind 绑定器

`std::bind` 用于将可调用对象与其参数一起绑定,形成一个新的可调用对象。绑定后的结果可以使用 `std::function` 进行保存,并延迟调用到任何需要的时候。

`std::bind` 主要有两个作用:

1. 将可调用对象与其参数一起绑定成一个仿函数。
2. 将多元(参数个数为 n,n > 1)可调用对象转成一元或者(n-1)元可调用对象,即只绑定部分参数。

```cpp
void call_when_even(int x, const std::function& f) {
if (!(x & 1)) {
f(x);
}
}

void output(int x) {
cout <}

void output_add_2(int x) {
cout <}

int main() {
{
auto fr = std::bind(output, std::placeholders::_1);
for (int i = 0; i <10; ++i) {
call_when_even(i, fr);
}
}
cout < {
auto fr = std::bind(output_add_2, std::placeholders::_1);
for (int i = 0; i <10; ++i) {
call_when_even(i, fr);
}
}
return 0;
}
```

`std::bind` 可以看作是一个仿函数,如果在 `bind` 中给出了参数,则后面不再需要给出参数;如果给出的是占位符,则需要在调用时给出参数。

```cpp
void output(int x, int y) {
cout <}

int main() {
std::bind(output, std::placeholders::_1, std::placeholders::_2)(1, 2);
std::bind(output, std::placeholders::_2, std::placeholders::_1)(1, 2);
return 0;
}
```

### 实际应用示例

下面是一个实际应用示例,展示了如何使用 `std::bind` 和 `std::function` 来处理任务队列:

```cpp
void output(int x, int y, int& z) {
cout <<"x: " < z = x + y;
}

using Task = std::function;
std::list g_tasklist;

void thread_func() {
cout <<"thread begin" < while (!g_tasklist.empty()) {
Task task = g_tasklist.front();
g_tasklist.pop_front();
task(); // 调用任务
}
}

int main() {
int a = 10, b = 20;
int z = 0;
Task t1 = std::bind(output, a, b, std::ref(z));
g_tasklist.push_back(t1);
std::thread tha(thread_func);
tha.join();
cout < return 0;
}
```

通过 `std::bind` 和 `std::function`,我们可以更灵活地处理各种可调用对象,提高代码的复用性和可维护性。
推荐阅读
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • 本文详细探讨了VxWorks操作系统中双向链表和环形缓冲区的实现原理及使用方法,通过具体示例代码加深理解。 ... [详细]
  • Linux设备驱动程序:异步时间操作与调度机制
    本文介绍了Linux内核中的几种异步延迟操作方法,包括内核定时器、tasklet机制和工作队列。这些机制允许在未来的某个时间点执行任务,而无需阻塞当前线程,从而提高系统的响应性和效率。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 数据库内核开发入门 | 搭建研发环境的初步指南
    本课程将带你从零开始,逐步掌握数据库内核开发的基础知识和实践技能,重点介绍如何搭建OceanBase的开发环境。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • C++: 实现基于类的四面体体积计算
    本文介绍如何使用C++编程语言,通过定义类和方法来计算由四个三维坐标点构成的四面体体积。文中详细解释了四面体体积的数学公式,并提供了两种不同的实现方式。 ... [详细]
  • 本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 本题涉及一棵由N个节点组成的树(共有N-1条边),初始时所有节点均为白色。题目要求处理两种操作:一是改变某个节点的颜色(从白变黑或从黑变白);二是查询从根节点到指定节点路径上的第一个黑色节点,若无则输出-1。 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
author-avatar
平凡小迪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有