cocos2d-x v3.3 CallFunc and CallFuncN

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_*()适用于类的成员函数,不适用于全局函数和普通函数。因为它会默认绑定一个调用者的指针,类的成员函数需要这个指针调用,而全局函数和普通函数不需要。