1. 程式人生 > >Cocos2dx 3.0 過渡篇(十七) std::bind與CC_CALLBACK不得不說的故事

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到底是什麼?除錯如圖:


好吧,先讓我回口血,然後再來回答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!");
}	


恩,就是這樣子了。bind與CC_CALLBACK之間的關係就是這麼的...簡單。