在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++中的可调用对象的更多相关文章

  1. ruby中的可调用对象--方法

    上一篇讲了ruby中的可调用对象proc和lambda,他们都是块转换成的对象.ruby中的可调用对象还有方法.通过使用method方法,并且以方法名作为参数(字符串或者符号),就可以得到一个方法对象 ...

  2. ruby中的可调用对象--proc和lamdba

    ruby中将块转变成对象的三种方法 ruby中的大部分东西都是对象,但是块不是.那么,如果你想存下来一个块,方便以后使用,你就需要一个对象.ruby中有三种方法,把块转换成可以利用的对象. Proc. ...

  3. Delphi 中的DLL 封装和调用对象技术(刘艺,有截图)

    Delphi 中的DLL 封装和调用对象技术本文刊登2003 年10 月份出版的Dr.Dobb's 软件研发第3 期刘 艺摘 要DLL 是一种应用最为广泛的动态链接技术但是由于在DLL 中封装和调用对 ...

  4. C++之可调用对象

    C++中的可调用对象分为以下几种: 函数 函数指针 lambda表达式 bind创建的对象 重载了函数调用运算符(即“()”)的类 函数.函数指针不再介绍.lambda表达式与bind创建的类参考—— ...

  5. C++中的各种可调用对象

    概述 一组执行任务的语句都可以视为一个函数,一个可调用对象.在程序设计的过程中,我们习惯于把那些具有复用性的一组语句抽象为函数,把变化的部分抽象为函数的参数. 函数的使用能够极大的极少代码重复率,提高 ...

  6. Python中的7种可调用对象

    Python中有七种可调用对象,可调用对象可使用内置函数callable来检测 一.用户自定义的函数: 使用def语句或者lambda表达式创建的函数. 二.内置函数: 使用C语言实现的函数,如len ...

  7. C/C++: C++可调用对象详解

    C++中有几种可调用对象:函数,函数指针,lambda表达式,bind创建的对象,以及重载了函数调用符的类. 1. 函数 函数偏基础的东西,在这里不再叙述.重点讲下C++11的某些重要特性和函数指针. ...

  8. 深入理解Javascript中构造函数和原型对象的区别

    在 Javascript中prototype属性的详解 这篇文章中,详细介绍了构造函数的缺点以及原型(prototype),原型链(prototype chain),构造函数(constructor) ...

  9. C#中考虑为大对象使用弱引用

    1.无论怎样尽力,我们总是会使用到某些需要大量内存的数据,而这些内存并不需要经常访问.或许你需要从一个大文件中查找某个特定的值,或者算法需要一个较大的查询表.这时,你也许会采用2中不太好做法:第一种是 ...

随机推荐

  1. java判断两个时间相差得天数

    方法一:通过Calendar类得日期比较,在这需要考虑闰年和平年,也要考虑跨年份 /** * date2比date1多的天数 * @param date1 * @param date2 * @retu ...

  2. mybatis批量插入和更新

    批量插入 <insert id="add" parameterType="java.util.List"> insert all <forea ...

  3. linux 命令——screen

    最近遇到一个东西aria2,这个玩意,这个是啥呢?Aria2是一个轻量级Linux下载软件,支持HTTP/HTTPS, FTP, SFTP, BitTorrent和磁力链接(官方版),公司系统插件配套 ...

  4. 微信小程序解析HTML标签带有<p>

    小程序中默认是不支持html格式没有<p>标签,但是有些接口需要返回带有标签的,例如 : 隐私协议: 解决方法: 小程序中有一个富文本标签组件,前端可以解析H5标签就是 rich-text ...

  5. 如何重启Cisco LAP?

    在Cisco WLC上进入对应的AP,能够看到Reset这个AP,但是这里会有两种选择: 看到上述的描述,可能很多人都不敢轻易的操作: 1.Hardware Reset:Perform a hardw ...

  6. plupload上传视频插件jQuery+php

    我在网上找到一个很好的视频上传插件,经过我的一些整理.补充,在这里分享给大家. 这个视频插件是新浪微博plupload上传视频插件,支持格式有mpg,m4v,mp4,flv,3gp,mov,avi,r ...

  7. 解决 上下拉的橡皮筋 和 复制无效 和 ios滑动屏幕定时器停止问题cordova

    cordova 安装插件cordova plugin add cordova-plugin-wkwebview-engine@latest --save config.xml 的 <platfo ...

  8. Mac 配置 React Native 环境

    OSX系统,这里假定你是iOS开发人员 Homebrew 是需要的,只有安装了Homebrew才能继续安装watchman和flow 安装 Node.js 4.0 或者更新的版本. 使用 Homebr ...

  9. python两个_多个字典合并相加

    这只是符合比较正常的需求和场景. #一.适用合并两个字典(key不能相同否则会被覆盖),简单,好用. A = {'a': 11, 'b': 22} B = {'c': 48, 'd': 13} #up ...

  10. ubuntu 16 “无法获得锁”解决方案

    强制解锁,命令 sudo rm /var/cache/apt/archives/lock sudo rm /var/lib/dpkg/lock