C++的成员函数指针与Cococs2d-x的selector机制

在Cocos2d-x中点击某个按钮要执行一个回调函数时,一般的写法是以下这样 : 

    // add a "share" icon to exit the progress. it's an autorelease object
    CCMenuItemImage *pShareItem = CCMenuItemImage::create(
                                                          "share.png",
                                                          "share.png",
                                                          this,
                                    menu_selector(HelloWorld::menuShareCallback));

其中的HelloWorld::menuShareCallback是HelloWorld类的一个函数, 生命为 : 

    // a selector callback to share button
    void menuShareCallback(CCObject* pSender);

这个menuShareCallback就相当与Java中Listener的回调函数, 那么Cocos2d-x的selector机制是如何实现的呢 ?

要明白selector机制, 我们首先要清楚C/C++语言中的函数指针, 函数指针其实就是指向函数的指针。 在C/C++中, 函数会以内存地址来标识, 从函数的内存地址开始执行就相当于执行该函数。那么用什么来代表函数指针的地址呢, 其实C/C++语言中的函数名就代表了函数在内存中的地址。看下面的例子 : 

#include <iostream>

// 定义一个函数指针类型, MethodPointer
typedef void (*MethodPointer)(int num);

// 普通函数
void printNum(int num)
{
    cout << "The num is : " <<num<<endl;
}

int main(int argc, const char * argv[])
{
    
    MethodPointer mp = printNum;
    mp(444);
    
    return 0;
}
在文件的上面我们定义了一个函数指针类型MethodPointer,和它对应的函数类型应该是没有返回值的,且有一个Int参数的函数, 例如上文中的void printNum(int num)函数, 在main中我们定义了一个MethodPointer指针,指向了printNum方法,然后执行mp(444);就相当于执行了printNum(444)方法。 




对于C++来说还有一种是成员函数指针,它与C中的函数指针类似, 只是指针指向的是某个类中的成员函数。看下面这个例子 :

头文件

#ifndef __MenberCallback__MemberPointer__
#define __MenberCallback__MemberPointer__

class MemberPointer;
// 定义一个成员函数指针
typedef void (MemberPointer::*MCallback)(int num);

#include <iostream>
class MemberPointer
{
public:
    MemberPointer();
    ~MemberPointer();
    void click(MCallback callback);
    void doSth(int code);
    
} ;

#endif /* defined(__MenberCallback__MemberPointer__) */

cpp 

#include <iostream>
#include "MemberPointer.h"
using namespace std;

MemberPointer::MemberPointer()
{
    
}

MemberPointer::~MemberPointer()
{
    
}

void MemberPointer::doSth(int code)
{
    cout<<"call back method.     "<<code<<endl;
}

void MemberPointer::click(MCallback callback)
{
    // 执行回调, 因为在callback中传递的是自身的回调函数doStn,所以直接用this
    (this->*callback)(888);
}

main函数  :
int main(int argc, const char * argv[])
{
    
    MemberPointer *mPointer = new MemberPointer();
    mPointer->click(&MemberPointer::doSth) ;
    
    return 0;
}


执行结果为 


可见, 在click方法中我们执行了doSth方法, 打印出了888这几个数字。


参考资料  :  成员函数指针 


最后模拟一下Cocos2d-x中按钮的selector的实现, 就直接上代码了。

CCObject.h

//
//  CCObject.h
//  membercallback
//
//  Created by mrsimple on 4/1/14.
//  Copyright (c) 2014 mrsimple. All rights reserved.
//

#ifndef __membercallback__CCObject__
#define __membercallback__CCObject__

#include <iostream>

class CCObject
{
public:
    CCObject();
    virtual ~CCObject();
} ;

// 定义回调函数为CCObject或者CCObject子类中的成员函数,两个参数
typedef void (CCObject::*ButtonCallback)(CCObject* pSender, int stCode);
// 定义selector
#define button_selector(_SELECTOR) (ButtonCallback)(&_SELECTOR)

#endif /* defined(__membercallback__CCObject__) */


CCObject.cpp

#include "CCObject.h"

CCObject::CCObject()
{
}

CCObject::~CCObject()
{
}

CCButton.h

//
//  CCButton.h
//  membercallback
//
//  Created by mrsimple on 4/1/14.
//  Copyright (c) 2014 mrsimple. All rights reserved.
//

#ifndef __membercallback__CCButton__
#define __membercallback__CCButton__

#include <iostream>
#include "CCObject.h"

class CCButton : public CCObject
{
public:
    CCButton();
    virtual ~CCButton();
    void click(CCObject* pSender);
    void setCallback(ButtonCallback callback );
    
private:
    void buttonClick(CCObject* pSender, int code) ;
    ButtonCallback _buttonCallback;
    CCObject* mSender;
} ;

#endif /* defined(__membercallback__CCButton__) */

CCButton.cpp

//
//  CCButton.cpp
//  membercallback
//
//  Created by mrsimple on 4/1/14.
//  Copyright (c) 2014 mrsimple. All rights reserved.
//

#include "CCButton.h"

using namespace std;

CCButton::CCButton()
:mSender(NULL)
{
}

CCButton::~CCButton()
{
    delete mSender;
}
// 设置回调函数
void CCButton::setCallback(ButtonCallback callback)
{
    _buttonCallback = callback ;
}

// 按钮点击操作, 执行回调
void CCButton::click(CCObject* pSender)
{
    mSender = pSender ;
    // 执行回调函数,这里执行的则是CCScene中的buttonCallback函数
    (mSender->*_buttonCallback)(mSender, 123);
}


CCScene.h

//
//  CCScene.h
//  membercallback
//
//  Created by mrsimple on 4/1/14.
//  Copyright (c) 2014 mrsimple. All rights reserved.
//

#ifndef __membercallback__CCScene__
#define __membercallback__CCScene__

#include <iostream>

#include <iostream>
#include "CCObject.h"
#include "CCButton.h"

class CCScene : public CCObject
{
public:
    CCScene();
    virtual ~CCScene();
    void clickButton();
private:
    CCButton* mButton;
    void buttonCallback(CCObject* pSender, int code);
};

#endif /* defined(__membercallback__CCScene__) */

CCScene.cpp

//
//  CCScene.cpp
//  membercallback
//
//  Created by mrsimple on 4/1/14.
//  Copyright (c) 2014 mrsimple. All rights reserved.
//

#include "CCObject.h"
#include "CCButton.h"
#include "CCScene.h"

using namespace std;

// 构造函数, 创建CCButton
CCScene::CCScene()
:mButton(new CCButton())
{
    // 设置回调函数
    mButton->setCallback( button_selector(CCScene::buttonCallback) ) ;
}

CCScene::~CCScene()
{
    delete  mButton ;
}


// 模拟点击按钮的操作
void CCScene::clickButton()
{
    if ( mButton != NULL )
    {
        // 按钮点击
        mButton->click(this) ;
    }
    
}

// 点击按钮, 回调该函数
void CCScene::buttonCallback(CCObject *pSender, int code)
{
    cout<<"In CCScene --> callback, code = "<<code<<endl;
}


main.cpp 使用示例 :

//
//  main.cpp
//  membercallback
//
//  Created by mrsimple on 4/1/14.
//  Copyright (c) 2014 mrsimple. All rights reserved.
//

#include <iostream>
#include "CCObject.h"
#include "CCScene.h"

int main(int argc, const char * argv[])
{

    CCScene* sc = new CCScene();
    sc->clickButton() ;
    
    return 0;
}
首先定义了CCObject类,该类为Cocos2d-x其他引用类型的基类,并且在头文件中定义了按钮的回调函数指针。CCButton中定义了按钮的点击函数,在该点击函数中执行对应的回调函数。在CCScene场景中添加一个按钮, 并且将该按钮点击的回调函数设置为CCScene类中的buttonCallback成员函数, 然后通过CCScene类中的clickButton函数来显式触发CCButton的click函数,CCButton对象会在click函数中执行点击按钮的回调( 即 CCScene类的buttonCallback函数 ), 最后输出结果。

输出结果 



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值