c++的可调用对象 有

  • 函数
  • 函数指针
  • lambda表达式
  • bind的对象
  • 重载了函数调用运算符的类

如何调用?

函数调用

void afuncToCall()
{
cout << "call me"<<"\n";
}
//1.call function
afuncToCall();

函数指针调用

void func(int i){
cout << "a function called by function pointer i= "<<i<<"\n";
}
//声明一个函数指针
void(*f)(int i);
//对函数指针赋值
f=func;
//调用指针函数
f(5);

或者使用typedef缩写函数指针

//function pointer
typedef void(*AbleCallFuncP)(int i) ;
//2.function pointer
AbleCallFuncP callFuncPointer= func;
callFuncPointer(5);

lambda表达式调用

auto flambda = [](int i){
cout << "lambda i is " << i << "\n";
};
flambda(7);

bind的对象

#include <functional>
void func(int i){
cout << "a function called by bind object i= "<<i<<"\n";
} auto fbind = bind(func,std::placeholders::_1);
fbind(9);

重载了函数调用运算符的类

struct callableStruct
{
int operator()(int val){
return (val<0)?-val:val;
}
};
// callableStruct callableSut;
int i = callableSut(-2);

函数表

现在,我们拥有了5种函数调用方式,那么,在一个项目里,我们很可能希望使用一个统一的函数表来管理这些函数调用对象,以上面的函数为例,我们其实拥有了5个参数为int类型的调用对象,使用map可以方便地实现函数表;

只是,问题在于,这5种可调用对象的类型是不同的,我们无法将他们使用同一种类型放入map的second字段中,于是万能的C++标准大神们发明了function类模板来解决这个问题。

罗列5种可调对象如下:

//function
void afuncToCall(int i)
{
cout << "call me a plain functon i is "<<i <<"\n";
}
//function pointer
typedef void(*AbleCallFuncP)(int i) ; //called by function pointer
void func1(int i){
cout << "a function called by function pointer i= "<<i<<"\n";
} //called by bind
void func2(int i){
cout << "a function called by bind i= "<<i<<"\n";
} //callable class
struct callableStruct
{
void operator()(int i){
cout << "a function called by callableStruct i= "<<i<<"\n";
}
};
//1.call function
//afuncToCall();
// //2.function pointer
AbleCallFuncP callFuncPointer= func1;
//3.lambda
auto flambda = [](int i){
cout << "lambda i is " << i << "\n";
};
//4 bind
auto fbind = bind(func2,std::placeholders::_1);
//5.operator ()
callableStruct callableSut;

让我们用function统一它们的类型

#include <functional>
#include <map>
#include <string>
// using std::map;
void TestCallableObj()
{
typedef function<void(int)> FuncVI;
typedef map<string,FuncVI> FuncAbleObjMap;
FuncAbleObjMap callableObjMap; callableObjMap.insert(FuncAbleObjMap::value_type(string("plain function call"),afuncToCall));
callableObjMap.insert(FuncAbleObjMap::value_type(string("function pointer call"),callFuncPointer));
callableObjMap.insert(FuncAbleObjMap::value_type(string("lambda call"),flambda));
callableObjMap.insert(FuncAbleObjMap::value_type(string("bind call"),fbind));
callableObjMap.insert(FuncAbleObjMap::value_type(string("operator() call"),callableStruct())); callableObjMap["plain function call"](1);
callableObjMap["function pointer call"](2);
callableObjMap["lambda call"](3);
callableObjMap["bind call"](4);
callableObjMap["operator() call"](5);
}

输出结果

call me a plain functon i is 1
a function called by function pointer i= 2
lambda i is 3
a function called by bind i= 4
a function called by callableStruct i= 5

由此可见,通过function模板,我们将类型本不同的5个可调用对象打包成统一的类型,因为它们的返回值和参数类型是完全一样的。通过函数表的使用,我们可以写出封装更好的调用函数。

如果觉得这样的调用太繁琐,可以使用宏来缩写下

比如:

#define CALL1(x)  callableObjMap[#x](1);
CALL1(plain function call);
CALL1(bind call);

备注,本文没有涉及到函数成员函数 和静态成员函数的调用,权当归类到函数一类了。但是其调用细节和函数还是有差异的。

C++可调用对象与函数表的更多相关文章

  1. C++ 关于类与对象在虚函数表上唯一性问题 浅析

    [摘要] 非常多教材上都有介绍到虚指针.虚函数与虚函数表.有的说类对象共享一个虚函数表,有的说,一个类对象拥有一个虚函数表.还有的说,不管用户声明了多少个类对象,可是,这个VTABLE虚函数表仅仅有一 ...

  2. C++对象内存模型2 (虚函数,虚指针,虚函数表)

    从例子入手,考察如下带有虚函数的类的对象内存模型: class A { public: virtual void vfunc1(); virtual void vfunc2(); void func1 ...

  3. 深入理解类成员函数的调用规则(理解成员函数的内存为什么不会反映在sizeof运算符上、类的静态绑定与动态绑定、虚函数表)

    本文转载自:http://blog.51cto.com/9291927/2148695 总结: 一.成员函数的内存为什么不会反映在sizeof运算符上?             成员函数可以被看作是类 ...

  4. C++对象的内存布局以及虚函数表和虚基表

    C++对象的内存布局以及虚函数表和虚基表 本文为整理文章, 参考: http://blog.csdn.net/haoel/article/details/3081328 http://blog.csd ...

  5. C++虚函数表解析(图文并茂,非常清楚)( 任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法)good

    C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术 ...

  6. C++虚函数表和对象存储

    C++虚函数表和对象存储 C++中的虚函数实现了多态的机制,也就是用父类型指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数,这种技术可以让父类的指针有"多种形态",这 ...

  7. C++对象内存模型2 (虚函数,虚指针,虚函数表)(转)

    class A { public: virtual void vfunc1(); virtual void vfunc2(); void func1(); void func2(); virtual ...

  8. C++对象内存分布详解(包括字节对齐和虚函数表)

    转自:https://www.jb51.net/article/101122.htm 1.C++对象的内存分布和虚函数表: C++对象的内存分布和虚函数表注意,对象中保存的是虚函数表指针,而不是虚函数 ...

  9. C++对象的内存分布和虚函数表

    c++中一个类中无非有四种成员:静态数据成员和非静态数据成员,静态函数和非静态函数. 1.非静态数据成员被放在每一个对象体内作为对象专有的数据成员.    2.静态数据成员被提取出来放在程序的静态数据 ...

随机推荐

  1. Spark UI (基于Yarn) 分析与定制

    转载自:https://yq.aliyun.com/articles/60194 摘要: 这篇文章的主旨在于让你了解Spark UI体系,并且能够让你有能力对UI进行一些定制化增强.在分析过程中,你也 ...

  2. Mybatis一对一映射

    一.Mybatis一对一映射 本例讲述使用mybatis开发过程中常见的一对一映射查询案例.只抽取关键代码和mapper文件中的关键sql和配置,详细的工程搭建和Mybatis详细的流程代码可参见&l ...

  3. cocos代码研究(22)Widget子类Layout学习笔记

    理论基础 一个包含控件的容器. 子节点可以根据布局类型重新排序,它还可以开启剪裁,设置背景图像和颜色.继承自Widget,以及LayoutProtocol. 被 HBox, PageView, Rel ...

  4. curl基本使用

    curl简介 linux curl是一个利用URL规则在命令行下工作的文件传输工具.它支持文件的上传和下载. curl可以使用URL的语法模拟浏览器来传输数据,因为它是模拟浏览器,因此它同样支持多种协 ...

  5. 系统管理命令之tty

    在Linux操作系统中,所有外围设备都有其名称与代号,这些名称代号以特殊文件的类型存放于/dev目录下.你可以执行tty指令查询目前使用的终端机的文件名称. 1.命令帮助: # tty -- help ...

  6. poj1434 Fill the Cisterns!

    地址:http://poj.org/problem?id=1434 题目:Fill the Cisterns! Fill the Cisterns! Time Limit: 5000MS   Memo ...

  7. Win10取消开机密码方法

    1.开始菜单输入命令“netplwiz” 2.进入到用户账户页面,选择所需账户,把“要使用本计算机,用户必须输入用户名和密码”单选框取消勾选,点击应用 3.输入密码进行 这个时候会提示输入两次该账户的 ...

  8. mysql数据库设置不区分大小写,启动方法

    用root帐号登录后,在/etc/my.cnf中的[mysqld]后添加添加lower_case_table_names=1,重启MYSQL服务,这时已设置成功:不区分表名的大小写: lower_ca ...

  9. linux及安全第六周总结——20135227黄晓妍

    总结部分: 操作系统内核三大功能: 进程管理,内存管理,文件系统 最核心的是进程管理 为了管理,首先要对每一个进程进行描述.进程描述符提供了所有内核需要了解的信息. 进程控制模块:task_struc ...

  10. JS封装简单后代选择器

    大概思路是这样的:通过判断传过来的参数是什么类型,如果是对象,那这里就是this(因为封装是自己用的,肯定不会随便乱传一个对象过来),如果是一个函数(匿名函数),那就是Dom加载(这里先不讲),如果是 ...