CallFunc和CallFuncN主要用于将一个类的成员函数创建为回调函数指针,并在该回调函数被调用时以合适的方式调用类的成员函数。
他们之间的区别就在于上面提到的“合适的方式”上。CallFunc接收std::function<void(void)>类型的成员函数,调用时也是简单的调用成员函数。而CallFuncN接收std::function<void(Node *)>类型的成员函数,调用时将调用者本身作为参数(即参数“Node *”)传递给被调用的成员函数。具体的实现看下面的源码分析吧。
下面看看他们的继承关系:
ActionInstant
|
CallFunc
|
CallFuncN
CallFuncN继承自CallFunc,CallFuncN算是CallFunc的功能延伸。
CallFunc和CallFuncN中有一些被废弃的源码,就不再分析了。
CallFunc:
其中一些get/set的成员方法,就不一一列举了。
一、成员变量:
protected:
std::function<void()> _function; // 存储类的成员函数。这里与CallFuncN::_function对比看。
private:
CC_DISALLOW_COPY_AND_ASSIGN(CallFunc); // 禁用拷贝构造函数。
二、成员方法:
(1) static CallFunc * create(const std::function<void()>& func);
创建类的成员函数创建的回调函数指针。
func:类的成员函数。
实例:
void A::foo(void)
{
...
}
Sprite *sprite = Sprite::create(...);
CallFunc *callfunc = CallFunc::create(CC_CALLBACK_0(A::foo, this));
this->addChild(sprite);
sprite->runAction(Sequence::create(..., callfunc, ..., nullptr));
实现源码:
CallFunc * CallFunc::create(const std::function<void()> &func)
{
CallFunc *ret = new (std::nothrow) CallFunc(); // 创建CallFunc的对象。
if (ret && ret->initWithFunction(func) ) { // 如果创建成功,则存储类的成员函数。
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
(2) bool initWithFunction(const std::function<void()>& func);
存储类的成员函数。
func:类的成员函数。
实现源码:
bool CallFunc::initWithFunction(const std::function<void()> &func)
{
_function = func;
return true;
}
(3) virtual void execute();
以合适的方式调用类的成员函数。
实现源码:
void CallFunc::execute() {
if( _function ){
_function(); // 这里与CallFuncN::execute()对比看。
}
}
(4) virtual void update(float time) override;
virtual CallFunc* reverse() const override;
virtual CallFunc* clone() const override;
这三个函数实现简单,并且使用几率比较小,在这里就不分析了。
CallFuncN:
CallFuncN与CallFunc类似,在此只列出有区别的部分。
一、成员变量:
protected:
std::function<void(Node *)> _functionN; // 存储类的成员函数。这里接收带一个Node*类型参数的类成员函数。
二、成员方法:
(1) virtual void execute() override;
以合适的方式调用类的成员函数。
实现源码:
void CallFunc::execute() {
if( _functionN ){
/* 这里的_target是Action::_target,即调用回调函数的节点。
* 这里将节点作为参数传递给类的成员函数,也即所说的“以合适的方式”。
- CallFunc的方式是单纯的调用类的成员函数;CallFuncN的方式是将调用者作为参数传递给类的成员函数。
*/
_functionN(_target); // 这里与CallFunc::execute()对比看。
}
}
CC_CALLBACK_*():
CC_CALLBACK_*()借助于std::bind()实现了创建类的成员函数指针的功能。
实现源码:
#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__)
__selector__:被绑定的类的成员函数。
__target__:成员函数所属于的类的指针(CLASS A; A a, *p; &a或者p)。
std::placeholders::_*:std::bind()中所使用的占位符。
__VA_ARGS__:C99规范中新增的可变参数的宏。宏前面加上##的作用在于,当可变参数的个数为0时,##可以把前面多余的","去掉。
此部分推荐阅读:
http://www.jellythink.com/archives/773
http://www.cnblogs.com/xusd-null/p/3698969.html
总结:
1、CallFunc继承自ActionInstant我想是为了让其子类CallFuncN能够获取到调用者(Action::_target,调用者执行runAction()时,Action::_target = 调用者)。
2、CC_CALLBACK_*()适用于类的成员函数,不适用于全局函数和普通函数。因为它会默认绑定一个调用者的指针,类的成员函数需要这个指针调用,而全局函数和普通函数不需要。