Cocos2dx 3.0 -- std::bind与CC_CALLBACK不得不说的故事

本篇的主题就是揭露CC_CALLBACK 与 std::bind之间不可告人的秘密…

首先看一段代码:

//先是创建3个精灵
boy = Sprite::create("boy.png");//创建boy
boy->setPosition(Point(visibleSize.width/2,visibleSize.height/2));
this->addChild(boy,1);

girl_1 = Sprite::create("girl_1.png");//创建girl1
girl_1->setPosition(Point(visibleSize.width/3,visibleSize.height/2));
girl_1->setTag(10);
this->addChild(girl_1,1);

girl_2 = Sprite::create("girl_3.png");//创建girl2
girl_2->setPosition(Point(2*visibleSize.width/3,visibleSize.height/2));
girl_2->setTag(20);
this->addChild(girl_2,1);

//让boy运动,通过Callfunc回调到callback1
boy->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,100)),
                                    CallFunc::create(CC_CALLBACK_0(HelloWorld::callback1,this)),
                                    NULL));


```



三个回调函数的实现:

void HelloWorld::callback1()
{
    CCLOG("in callback1");
    //girl1运动,最后回调到callback2
    girl_1->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,150)),
                                            CallFunc::create(CC_CALLBACK_0(HelloWorld::callback2,this,girl_1)),
                                            NULL));
}
void HelloWorld::callback2(Node* sender)
{
    //girl2运动,最后回调到callback3
    girl_2->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,200)),
        CallFunc::create(CC_CALLBACK_0(HelloWorld::callback3,this,girl_2,99)),
        NULL));

    CCLOG("in callback2,sender tag is:%d",(Sprite*)sender->getTag());
}
void HelloWorld::callback3(Node* sender, long data)
{
    //最终输出
    CCLOG("in callback3,everything is OK,sender tag is:%d,date is:%ld",(Sprite*)sender->getTag(),data);
    CCLOG("girl2 dandan ask:what fake the CC_CALLBACK is?");
}


```


整个过程就
是boy“勾引”girl1,但girl1显然对异性兴趣不大,于是她也勾引girl2......可是,girl2对同性异性都没兴趣,她只是淡淡的说了句:CC_CALLBACK到底是什么?,调试如图:

![](http://img.blog.csdn.net/20140314190413656?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3RhcnQ1MzA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)



好吧,先让我回口血,然后再来回答girl2的问题:CC_CALLBACK到底是什么碗糕(东东)?
我们先进CC_CALLBACK源码里看看:
// 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_CALLBACK_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_是可变参数宏,我就不多说了。重点讲的是std::bind。
std::bind是在C++ 11里新加入的成员。可以将bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表.
调用bind的一般形式为:
auto newCallback = bind(callback,arg_list);
其中,newCallback是一个可调用对象,arg_list是可以用逗号分隔的参数列表,至于是啥参数,那就看callback函数里有啥参数啦。也就是说,当我们调用newCallback时,newCallback会调用函数callback,并传递参数arg_list给callback.
看完上面的内容你的理解可能还比较模糊,那直接来个例子:有一个函数callback,如下,

int callback(int one,char two,double three);


```


下面我们用bind来调用callback

auto newCallback = bind(callback,_1,_2,1.5);
int x = newCallback(10,'h');  //这句相当于:int x = callback(10,'h',1.5);


```


“_1″是一个占位符对象,用于表示当函数callback通过函数newCallback进行调用时,函数newCallback的第一个参数在函数callback的参数列表中的位置。第一个参数称为”_1″, 第二个参数为”_2″,依此类推,有意思吧。至于‘1.5’是指默认参数,它处于_1和_2的后面,所以它就是double类型的参数了.
在强调一点就是:_1这类占位符都定义在一个名为placeholders的命名空间中,而这个命名空间本身定义在std的命名空间中。为了使用这些名字,两个命名空间都要写上,如:
std::placeholders::_1;

这样编写贼麻烦,所以在要使用_1时,可以加上这么一句:
using namespace namespace_name; 恩,ok

恩,bind就介绍到这,讲的比较浅,不理解的可以百度研究下。最后再回过头来看下CC_CALLBACK的定义,是不是清晰多了?
最后在举个例子吧,还是之前的boy,girl1,girl2,只是他们之间传递“爱意”的方式要换下了。不用CC_CALLBACK,改用std::bind。代码如下 :

//让boy运动,通过Callfunc回调到callback1
boy->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,100)),
                                    CallFunc::create(std::bind(&HelloWorld::callback1,this)),
                                    NULL));

```


void HelloWorld::callback1()
{
    CCLOG("in callback1");
    //girl1运动,最后回调到callback2
    girl_1->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,150)),
                                            CallFunc::create(std::bind(&HelloWorld::callback2,this,girl_1)),
                                            NULL));
    CCLOG("boy ask girl_1:can you do my girlFriends?");
}
void HelloWorld::callback2(Node* sender)
{
    //girl2运动,最后回调到callback3
    girl_2->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,200)),
        CallFunc::create(std::bind(&HelloWorld::callback3,this,girl_1,99)),
        NULL));

    CCLOG("in callback2,sender tag is:%d",(Sprite*)sender->getTag());
    CCLOG("girl_1 ask girl_2:I love girl_2");
}
void HelloWorld::callback3(Node* sender, long data)
{
    //最终输出
    CCLOG("in callback3,everything is OK,sender tag is:%d,date is:%ld",(Sprite*)sender->getTag(),data);
    CCLOG("girl2 dandan say:I know how to use CC_CALLBACK!");
}    


```



![](http://img.blog.csdn.net/20140314190428812?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3RhcnQ1MzA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


恩,就是这样子了。bind与CC_CALLBACK之间的关系就是这么的...简单。


原文地址:http://blog.csdn.net/start530/article/details/21245565

客官 你玩得真嗨。。girl1,2.。。

正好在学习3.0的

要搞清楚cocos 3.0,要先把C++0X搞定啊,装个VS2013吧先。:8:

大哥,不能调戏女孩,爽不。

LZ,你博客有差不多的帖子,不过很多细节好像没太注意,今天偶然看到这个,总算对CC_CALLBACK有了一定了理解。。。十分感谢···

CallFunc::create(CC_CALLBACK_0(HelloWorld::callback3,this,girl_2,99))
应该是:
CallFunc::create(CC_CALLBACK_2(HelloWorld::callback3,this,girl_2,99))吧
后面不是跟着两个参数吗?

嗯 不错 支持了

现在才看到你的回复》。。:12:也有人提出同样的问题,你看下这篇博客里的评论吧。
http://blog.csdn.net/star530/article/details/21245565

感觉还是用std::bind不会乱,CC_CALLBACK_N会有一个默认传参,也就是调用者。

嗯嗯,谢谢···

原来是c++11哦,失敬失敬!!

非常感谢…

学习中, 学习中

std::bind不会乱啊,js语言有bind函数,它俩的意思是一样的!谢谢楼主分享,mark

支持LZ,雅蠛蝶

今天真的学习了!!!

不得不说楼主很好狠强大

can you do my girlfriend…:8:

DAY DAY UP!:2: