- typedef void (CCObject::*SEL_CallFuncN)(CCNode*);// 帶執行者回調
- typedef void (CCObject::*SEL_CallFuncND)(CCNode*, void*); // 帶一個自定參數的回調
- typedef void (CCObject::*SEL_CallFuncO)(CCObject*);
- typedef void (CCObject::*SEL_MenuHandler)(CCObject*);
- typedef void (CCObject::*SEL_EventHandler)(CCEvent*);
- typedef int (CCObject::*SEL_Compare)(CCObject*);
- #define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(&_SELECTOR)
- #define callfunc_selector(_SELECTOR) (SEL_CallFunc)(&_SELECTOR)
- #define callfuncN_selector(_SELECTOR) (SEL_CallFuncN)(&_SELECTOR)
- #define callfuncND_selector(_SELECTOR) (SEL_CallFuncND)(&_SELECTOR)
- #define callfuncO_selector(_SELECTOR) (SEL_CallFuncO)(&_SELECTOR)
- #define menu_selector(_SELECTOR) (SEL_MenuHandler)(&_SELECTOR)
- #define event_selector(_SELECTOR) (SEL_EventHandler)(&_SELECTOR)
- #define compare_selector(_SELECTOR) (SEL_Compare)(&_SELECTOR)
本質上,就是函數指針的應用。
但是,我們知道,在C中,函數指針是很普遍的應用。一般函數的函數名就是指針,不過是常量,再定義一個函數指針就是一個變量,這個變量可以指向這一類函數的地址。
比如:
- typedef void (*func)(int x);
- void up(int s);
- func f= up;
- f(3);
func是個函數指針類型:返回值是void,參數是一個int的函數。所以func的變量可以指向所有這一類的函數。
這是C風格的函數指針。但是在cocos2d-x中的回調,雖然還是函數指針,但已經有所區別。准確點說應該是成員函數指針。那么這普通的函數指針還可以來調成員函數嗎?呵呵,如果能的話我就不用寫這篇文章了。
C風格的函數指針要想調用成員函數,那么這個成員函數如果是static的也可以(為什么靜態函數就可以,呵呵)。但是這樣的話就會破壞類的結構。看cocos2d-x的實現也不是這樣的。
這里說cocos2d-x的實現方式:
看上面的定義,如:typedef void (CCObject::*SEL_MenuHandler)(CCObject*);
看這個就應該大致可以知道它的實現了。
這個定義有點不一樣,就是這個函數是CCObject的成員函數。這就是成員函數指針的定義。
大家知道,成員函數不能像普通C風格的函數那樣調用,因為每個成員函數需要知道是哪個對象實例調用它的,隱含有一個this指針。這也解釋了為什么靜態函數可以用C風格的函數指針來回調,因為靜態函數不需要對象實例就可以調用,呵呵。
既然定義成員函數指針,那么要用這個指針變量來調用回調函數,還需不需要對象實例呢。毫無疑問,還是需要的。
所以還必須有一個回調對象,CCObject *m_pListener。
這樣調用:
- (m_pListener->*m_pSelector)(CCObject *param);
下面是我寫的一個demo,類似cocos2d-x的實現:
- #ifndef __TestCallBack__Person__
- #define __TestCallBack__Person__
- #include <iostream>
- #include <string>
- using namespace std;
- // 基類
- class Person {
- public:
- void name(string name);
- };
- // 定義基類的成員函數指針
- typedef void (Person::*SEL_CallFun)(string str);
- // 派生類
- class Student : public Person{
- private:
- string m_name;
- int m_age;
- public:
- Student(string name, int age);
- ~Student();
- // 回調
- void callBack(string str);
- // say方法,要調用回調函數。
- void say();
- protected:
- // 回調的執行者
- Person *m_pListen;
- // 回調函數指針
- SEL_CallFun m_pfnSelectior;
- };
實現:
- #include "Person.h"
- void Person::name(string name)
- {
- cout<<name<<endl;
- }
- Student::Student(string name, int age)
- {
- this->m_name = name;
- this->m_age = age;
- }
- Student::~Student()
- {
- }
- void Student::say()
- {
- cout<<"Hi this is a Student"<<endl;
- // 回調函數指針賦值。需要強轉成 SEL_CallFun
- m_pfnSelectior = (SEL_CallFun)(&Student::callBack);
- // 回調的執行對象,傳this
- m_pListen = this;
- // 調用回調,參數是個string
- (m_pListen->*m_pfnSelectior)(m_name);
- }
- // 成員函數,要回調的函數
- void Student::callBack(string str)
- {
- cout<<"My name is "
- << str<<endl
- << "age is "
- <<m_age<<endl;
- }
main
- #include <iostream>
- #include "Person.h"
- int main(int argc, const char * argv[])
- {
- Student *a = new Student("Join",20);
- a->say();
- return 0;
- }
輸出:
- Hi this is a Student
- My name is Join
- age is 20
如果再定義一個宏:
- #define callFunc_selector(_SELECTOR) (SEL_CallFun)(&_SELECTOR)
那么調用就改成:
- m_pfnSelectior = callFunc_selector(Student::callBack);
這個就是cocos2d-x的回調實現模式了。呵呵
仔細看看,是不是一樣。