CC_CALLBACK原理及应用
c++ 11 基础 :
std::function
类模版 std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标进行存储、复制、和调用操作,这些目标包括函数、lambda表达式、绑定表达式、以及其它函数对象等。
用法示例:
①保存自由函数
void printA(int a){
cout<<a<<endl;
}
std::function<void(int a)> func;
func = printA;
func(2);
运行输出: 2
②保存lambda表达式
std::function<void()> func_1 = [](){cout<<"hello world"<<endl;};
func_1();
运行输出:hello world
③保存成员函数
struct Foo {
Foo(int num) : num_(num) {}
void print_add(int i) const { cout << num_+i << '\n'; }
int num_;
};
// 保存成员函数std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
Foo foo(2);
f_add_display(foo, 1);
运行输出: 3
bind bind是一组用于函数绑定的模板。在对某个函数进行绑定时,可以指定部分参数或全部参数,也可以不指定任何参数,还可以调整各个参数间的顺序。对于未指定的参 数,可以使用占位符_1、_2、_3来表示。_1表示绑定后的函数的第1个参数,_2表示绑定后的函数的第2个参数,其他依次类推。
下面通过程序例子了解一下用法:
#include <iostream>using namespace std;
class A
{
public:
void fun_3(int k,int m){
cout<<k<<" "<<m<<endl;
}
};
void fun(int x,int y,int z){
cout<<x<<" "<<y<<" "<<z<<endl;
}
void fun_2(int &a,int &b){
a++;
b++;
cout<<a<<" "<<b<<endl;
}
int main(int argc, const char * argv[]){
auto f1 = bind(fun,1,2,3); //表示绑定函数 fun 的第一,二,三个参数值为: 1 2 3
f1(); //print:1 2 3auto f2 = bind(fun, placeholders::_1,placeholders::_2,3);
//表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f2 的第一,二个参数指定
f2(1,2);//print:1 2 3auto f3 = bind(fun,placeholders::_2,placeholders::_1,3);
//表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f3 的第二,一个参数指定//注意: f2 和 f3 的区别。
f3(1,2);//print:2 1 3int n = 2;
int m = 3;
auto f4 = bind(fun_2, n,placeholders::_1);
f4(m); //print:3 4cout<<m<<endl;//print:4 说明:bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的cout<<n<<endl;//print:2 说明:bind对于预先绑定的函数参数是通过值传递的
A a;
auto f5 = bind(&A::fun_3, a,placeholders::_1,placeholders::_2);
f5(10,20);//print:10 20std::function<void(int,int)> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2);
fc(10,20);//print:10 20return 0;
}
CC_CALLBACK
一、通过 HelloWorldScene 中的 closeItem 开始
在cocos2d-x 2.x 版本中:
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback));
在cocos2d-x 3.0 版本中:
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
void HelloWorld::menuCloseCallback(Object* pSender)
{
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
注意到在3.0版本中使用到 CC_CALLBACK_1 这样一个宏定义。
// new callbacks based on C++11#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALCC_CALLBACK_1(HelloWorld::menuCloseCallback,this)LBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3 ##__VA_ARGS__)
这里主要注意两点:一是 std::bind,二是##_VA_ARGS_; ##_VA_ARGS_是可变参数宏
原来还有 CC_CALLBACK_0 1 2 3;而其中又有什么区别呢?
1、首先我们看看3.0版本中MenuItemImage的create方法:
MenuItemImage * MenuItemImage::create(const std::string& normalImage, const std::string& selectedImage, const ccMenuCallback& callback)
其中的回调参数是 ccMenuCallback
typedef std::function<void(Object*)> ccMenuCallback
来这里使用到了 C++ 中的 function 语法。
注意到 在 CC_CALLBACK_ 的宏定义的中使用到的是 C++ 的 bind 语法,怎么不一致了呢? -- 见下面第四点 function
2、看回 CC_CALLBACK_ 的宏定义
原来 CC_CALLBACK_ 的宏定义中后面的 0 1 2 3分别表示的是 不事先指定回调函数参数的个数。
例如说 CC_CALLBACK_ 1 表示的是,回调函数中不事先指定参数是一个,而事先指定的回调函数的参数 可以任意多个。
而且要注意到其中 不指定回调函数参数 和 指定回调函数参数 的顺序,注意不事先指定的在前,事先指定的在后。
下面通过例子说明这一点:
假设回调函数:
// a selector callbackvoid menuCloseCallback(Object* pSender,int a,int b);
void HelloWorld::menuCloseCallback(Object* pSender,int a,int b)
{
std::cout<<a<<" "<<b<<std::endl;
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)exit(0);
#endif
}
注意到在回调函数中输出 a b
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback,this,1,2));
注意中其中 指定了两个参数 1 2
运行,在 点击closeItem 的时候,就会输出这两个事先指定的参数 1 2。
那么,不事先指定的参数是在什么时候传入的呢?
void MenuItem::activate()
{
if (_enabled)
{
if( _callback )
{
_callback(this);
}
if (kScriptTypeNone != _scriptType)
{
BasicScriptData data(this);
ScriptEvent scriptEvent(kMenuClickedEvent,&data);
ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&scriptEvent);
}
}
}
注意到其中的 _callback(this); 对了,这个时候就传入了 这个不事先指定的回调函数参数。
这样,closeItem 的回调函数的 void HelloWorld::menuCloseCallback(Object* pSender,int a,int b) 的三个参数都知道了。
第一个 不事先指定,在menu item调用 activate 的时候,_callback(this) 传入,this 也即是这个 menu item;第二、三个参数是事先指定的 1,2。
已经知道 CC_CALLBACK_ 的宏定义是 std::bind 那么我们可以直接使用std::bind。
如下:
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
std::bind(&HelloWorld::menuCloseCallback, this,std::placeholders::_1,1,2));
CC_CALLBACK原理及应用的更多相关文章
- 奇异值分解(SVD)原理与在降维中的应用
奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...
- node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理
一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...
- 线性判别分析LDA原理总结
在主成分分析(PCA)原理总结中,我们对降维算法PCA做了总结.这里我们就对另外一种经典的降维方法线性判别分析(Linear Discriminant Analysis, 以下简称LDA)做一个总结. ...
- [原] KVM 虚拟化原理探究(1)— overview
KVM 虚拟化原理探究- overview 标签(空格分隔): KVM 写在前面的话 本文不介绍kvm和qemu的基本安装操作,希望读者具有一定的KVM实践经验.同时希望借此系列博客,能够对KVM底层 ...
- H5单页面手势滑屏切换原理
H5单页面手势滑屏切换是采用HTML5 触摸事件(Touch) 和 CSS3动画(Transform,Transition)来实现的,效果图如下所示,本文简单说一下其实现原理和主要思路. 1.实现原理 ...
- .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理
.NET Core中间件的注册和管道的构建(1)---- 注册和构建原理 0x00 问题的产生 管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理.会话管理 ...
- python自动化测试(2)-自动化基本技术原理
python自动化测试(2) 自动化基本技术原理 1 概述 在之前的文章里面提到过:做自动化的首要本领就是要会 透过现象看本质 ,落实到实际的IT工作中就是 透过界面看数据. 掌握上面的这样的本领 ...
- CRC、反码求和校验 原理分析
3月份开始从客户端转后台,算是幸运的进入全栈工程师的修炼阶段.这段时间一边是老项目的客户端加服务器两边的维护和交接,一边是新项目加加加班赶工,期间最长经历了连续工作三天只睡了四五个小时的煎熬,人生也算 ...
- 菜鸟学Struts2——Struts工作原理
在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...
随机推荐
- php Laravel windows安装
先要装一个composer, 如果不会装请看这里composer windows可以直接下载composer-setup.exe, 如果安装失败提示"Unable to connect to ...
- Python生成器与yield
列表推导与生成器表达式 当我们创建了一个列表的时候,就创建了一个可以迭代的对象: >>> squares=[n*n for n in range(3)] >>> f ...
- PHP的(Thread Safe与Non Thread Safe)
在安装xdebug到时候你会有有TS和NTS版本的选择,在以前还有VC6和VC9的版本.如果你没有根据你目前的服务器的状况选择对应的版本的话,那么xdebug是安装不成功的. 一.如何选择 php5. ...
- FastScroll(2)不分组的listview 打开fastscroll的分组提示功能
本文只让fastscroll具有提示分组功能,但listview并不显示分组,如果想让分组的listview显示fastscroll,看下篇. 1,在listview中打开fastscroll 2,自 ...
- Java面试题-并发工具
1. 如何实现一个流控程序,用于控制请求的调用次数?
- ngui 脚本绘制sprite
public GameObject _background; public UIAtlas atlas; private Dictionary<int, UISprite> _allCar ...
- The only legal comparisons are between two numbers, two strings, or two dates.
The only legal comparisons are between two numbers, two strings, or two dates. Left hand operand is ...
- Excel 内容粘贴到DataGridView, DataGridView 粘贴到 Excel
void dataGridView1_KeyDown(object sender, KeyEventArgs e) { if (e.Control && e.KeyCode == Ke ...
- apache开源项目--Sirona
Apache Sirona 为 Java 应用程序提供了一个简单但可扩展的监控解决方案. apache / sirona
- apache开源项目--Mahout
Apache Mahout 是 Apache Software Foundation (ASF) 开发的一个全新的开源项目,其主要目标是创建一些可伸缩的机器学习算法,供开发人员在 Apache 在许可 ...