C++中的可调用对象
在C++中,常常会利用函数来简化程序流程。函数的存在使得C++整体更加“模块化”,因而也使得代码可读性大大提高。
在C++程序中,常常会很灵活地调用函数来实现不同的功能与目的(函数重载、继承多态等等)。在一些情况下,可以传入类似函数一样的可调用对象,使得这一用法更加强大。
下面是简单整理的几种调用方法:
首先,给定一个共同的前提。标准库提供了排序算法来帮助设计者实现基础的排序,如果设计者希望更加灵活地按照自定义的排序方式来调用标准函数进行排序,就可以在标准排序函数中,传入一个指向自定义的可调用对象即可。
下面,就依照这个前提,实现对一组int元素的升序排序,这里使用std::vector<int>来进行装载,即目标是让这个vector中的元素按照升序重新排列。
1. 使用Lambda:
事实上,在C++中,Lambda表达式就可以理解成生成一个可调用函数,而且这个函数是inline的。当然,这里可以直接把它作为一个可调用对象来使用。

2. 通过函数名直接调用自定义函数:
通过传入一个自定义函数的名字(编译器会自动将其转换成函数指针类型),可以达到直接调用该自定义函数的目的。
首先,根据这个前提定义一个名为isLess的函数,就像这样:

然后,直接传入这个函数的名字(isLess)即可:

3. 传入指向自定义函数的函数指针:
类似于2,传入指向这个自定义函数的函数指针也可以调用这个可调用对象。
当然,首先定义一个指向这个函数的函数指针:

然后,就像调用函数一样,传入这个函数指针就可以了:

4. 使用标准库bind函数来生成一个可调用对象,进而对其调用:
std::bind函数可以根据一个已定义的函数,生成一个可调用对象,这个可调用对象的传入参数列表可以自己定义与设计。更炫酷的是,这个参数列表不一定非要和被绑定的函数参数列表一致!

5. 使用自定义的可调用对象:
或许这听起来有点儿意思,事实上的确如此。用户可自定义一个可调用对象,只需要重载这个对象的类的()符号。相信我,尽管C++的重载运算符算是比较复杂的操作,但其中乐趣无穷。
这里,简单地定义一个需要的类(当然,我们需要的重点是这个类一定要重载()符号,毕竟这才是调用对象的重头戏):

然后,在主调函数中,要实例化一个这个类的对象(所以才能称之为可调用“对象”嘛...),只需要简单地将这个对象看作是一个“可调用函数”就ok了!

6. 使用标准库定义的可调用对象:
既然说到了自定义可调用对象,那么标准库中很可能已经有相关的基本实现了。标准库提供了标准库中很多类型的基本操作的可调用对象,很多时候,对于简单的内置类型,需要相关操作时只需要简单地调用标准库提供的可调用对象即可。

以上就是简单地设计生成/调用可调用对象的几种方法,当然,有的时候不同的方法带来的效益可能不同,适时地使用相应的可调用对象可以极大地简化程序。
下面附上上述所有方案的代码,包含的头文件以及实现文件,需要自己来写。当然,都是一些简单的操作,看官自行写一写就好。
#include "modnar.h" #include "show.cpp"
#include "random.cpp" bool isLess(const int &a, const int &b) {
return a < b;
} class CompareObj {
public:
CompareObj() = default;
bool operator()(const int &a, const int &b) {
return a < b;
}
}; int main(int argc, char *argv[]) {
std::vector<int> vec();
bool (*pf)(const int &, const int &) = isLess;
// You can also get "pf" like this:
// decltype(isLess) *pf = isLess; // Method1. Use Lambda expression.
modnar::get_rand_seq(vec);
std::sort(vec.begin(), vec.end(),
[](const int &a, const int &b) { return a < b; });
modnar::show(vec); // Method2. Call a function by its name.
modnar::get_rand_seq(vec);
std::sort(vec.begin(), vec.end(), isLess);
modnar::show(vec); // Method3. Call a function by using a function pointer to it.
modnar::get_rand_seq(vec);
std::sort(vec.begin(), vec.end(), pf);
modnar::show(vec); // Method4. Use std::bind function to generate a callable object.
modnar::get_rand_seq(vec);
std::sort(vec.begin(), vec.end(),
std::bind(isLess, std::placeholders::_1, std::placeholders::_2));
modnar::show(vec); // Method5. Use a self-defined callable object.
CompareObj *comp = new CompareObj();
modnar::get_rand_seq(vec);
std::sort(vec.begin(), vec.end(), *comp);
modnar::show(vec); // Method6. Use the callable object provided by standard library.
modnar::get_rand_seq(vec);
std::sort(vec.begin(), vec.end(), std::less<int>());
modnar::show(vec); return ;
}
Main.cpp
若有相关内容的想法与方法,以及对文章的建议与异议,请评论区分享你的idea,提前说声谢谢。
@编辑于2019.3.8
C++中的可调用对象的更多相关文章
- ruby中的可调用对象--方法
上一篇讲了ruby中的可调用对象proc和lambda,他们都是块转换成的对象.ruby中的可调用对象还有方法.通过使用method方法,并且以方法名作为参数(字符串或者符号),就可以得到一个方法对象 ...
- ruby中的可调用对象--proc和lamdba
ruby中将块转变成对象的三种方法 ruby中的大部分东西都是对象,但是块不是.那么,如果你想存下来一个块,方便以后使用,你就需要一个对象.ruby中有三种方法,把块转换成可以利用的对象. Proc. ...
- Delphi 中的DLL 封装和调用对象技术(刘艺,有截图)
Delphi 中的DLL 封装和调用对象技术本文刊登2003 年10 月份出版的Dr.Dobb's 软件研发第3 期刘 艺摘 要DLL 是一种应用最为广泛的动态链接技术但是由于在DLL 中封装和调用对 ...
- C++之可调用对象
C++中的可调用对象分为以下几种: 函数 函数指针 lambda表达式 bind创建的对象 重载了函数调用运算符(即“()”)的类 函数.函数指针不再介绍.lambda表达式与bind创建的类参考—— ...
- C++中的各种可调用对象
概述 一组执行任务的语句都可以视为一个函数,一个可调用对象.在程序设计的过程中,我们习惯于把那些具有复用性的一组语句抽象为函数,把变化的部分抽象为函数的参数. 函数的使用能够极大的极少代码重复率,提高 ...
- Python中的7种可调用对象
Python中有七种可调用对象,可调用对象可使用内置函数callable来检测 一.用户自定义的函数: 使用def语句或者lambda表达式创建的函数. 二.内置函数: 使用C语言实现的函数,如len ...
- C/C++: C++可调用对象详解
C++中有几种可调用对象:函数,函数指针,lambda表达式,bind创建的对象,以及重载了函数调用符的类. 1. 函数 函数偏基础的东西,在这里不再叙述.重点讲下C++11的某些重要特性和函数指针. ...
- 深入理解Javascript中构造函数和原型对象的区别
在 Javascript中prototype属性的详解 这篇文章中,详细介绍了构造函数的缺点以及原型(prototype),原型链(prototype chain),构造函数(constructor) ...
- C#中考虑为大对象使用弱引用
1.无论怎样尽力,我们总是会使用到某些需要大量内存的数据,而这些内存并不需要经常访问.或许你需要从一个大文件中查找某个特定的值,或者算法需要一个较大的查询表.这时,你也许会采用2中不太好做法:第一种是 ...
随机推荐
- 改变input[type=range]的样式 动态滑动
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...
- STM32开发记录
一.使用keil时经常遇到的问题 1.没有下载固件包 2.下载器没选择对 3.没安装下载器的驱动 二.关于数据手册和开发手册 1.如何下载这些手册 在官网下载,官网永远是一手资源 意法半导体官网:ww ...
- cnpm - 解决 " cnpm : 无法加载文件 C:\Users\93457\AppData\Roaming\npm\cnpm.ps1,因为在此系统上禁止运行脚本。有关详细信息 。。。 "
1.在win10 系统中搜索框 输入 Windos PowerShell选择 管理员身份运行 2,打开了powershell命令行之后,输入 set-ExecutionPolicy RemoteSig ...
- 具体的client-server通信模型以及最为常用的通信模式
实现虚拟网络服务的主要技术,指出IP负载均衡技术是在负载调度器的实现技术中效率最高的. 在已有的IP负载均衡技术中: 1)有通过网络地址转换(Network Address Translation)将 ...
- python中for循环中的循环变量
废话不多说,代码伺候: for i in range(3): print("hello") print(i) 运行结果如下: 从上面的例子可以看出,for循环里面的循环变量i作用域 ...
- gatling高性能测试工具
使用mvn命令直接测试. (loadrunner-----) 1.新建maven工程 2.在pom中导入依赖 <dependencies> <dependency> < ...
- spring web 测试用例
spring web 测试有三种方式 1. 自己初始化 MockMvc 2.依赖@springbootTest 它会帮你生产 webTestClient ,只需自己注入即可. 3.启动的时候,不加载整 ...
- Codeforces Round #619 (Div. 2) B. Motarack's Birthday
Dark is going to attend Motarack's birthday. Dark decided that the gift he is going to give to Motar ...
- 热部署简介及在eclipse安装插件JRebel进行热部署
一.热部署简介 1.热部署与热加载在应用运行的时候升级软件,无需重新启动的方式有两种,热部署和热加载.它们之间的区别是:(1).部署方式: 热部署在服务器运行时重新部署项目.热加载在运行时重新加载cl ...
- 夯实Java基础(二十五)——JDBC使用详解
1.JDBC介绍 JDBC的全称是Java Data Base Connectivity(Java数据库连接).是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问(例如MyS ...