在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. async 异步协程进阶

    协程通过 async/await 语法进行声明,是编写异步应用的推荐方式 例如新定义一个协程(coroutine object): async def foo(): return 42 首先先来介绍下 ...

  2. java web编写四则运算

    首先先画出一个表 <%@ page language="java" contentType="text/html; charset=UTF-8" page ...

  3. 学习笔记(24)- plato-训练中文模型

    先处理中文语料.参考上篇笔记 1. 准备model_definition_file文件 官方文档给了例子, plato/example/config/ludwig/metalWOZ_seq2seq_l ...

  4. 定时备份mysql数据库的shell脚本

    最近项目需要定时备份mysql数据库的数据,根据需求写了一份定时备份mysql数据库的脚本. -h mysql的地址  默认为localhost -P 端口号  默认为3306 -u 用户  默认为r ...

  5. 洛谷 P5016 龙虎斗(模拟)

    嗯... 题目链接:https://www.luogu.org/problem/P5016 这道题是一道模拟,不要考虑复杂,直接暴力枚举每一个点,看看加上s2之后两个势力的差值,找最小,记录下标. 注 ...

  6. 批量离线安装jar 包到maven本地仓库

    //installer.bat@echo offset localdir=%~dp0call mvn install:install-file -DgroupId=org.zhixun -Dartif ...

  7. js中this,箭头函数和普通函数

    四种基本用法 1. 一般方法中,this代指全局对象 window 2. 作为对象方法调用,this代指当前对象 3. 作为构造函数调用,this 指代new 出的对象 function test() ...

  8. Linux - 删除文件的正确方式

    mv <file> /tmp/ cp <file> /opt/file.bak rm

  9. ProtoBuf试用与JSON的比较

    介绍 ProtoBuf 是google团队开发的用于高效存储和读取结构化数据的工具.什么是结构化数据呢,正如字面上表达的,就是带有一定结构的数据.比如电话簿上有很多记录数据,每条记录包含姓名.ID.邮 ...

  10. PHP弱类型(一)

    如图,id的值必须满足上述表达式,才能返回想要的值 与运算,只要出现false,整个表达式返回false 看见后面的==就想尝试一下弱类型绕过,参考资料:https://www.cnblogs.com ...