在cocos2d-x 引擎中 回调函数如下类型的 函数指针:
typedef void (CCObject::*SEL_SCHEDULE)(float);
typedef void (CCObject::*SEL_CallFunc)();
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*);
typedef void (CCObject::*SEL_CallGetPic)(unsigned char* lpData,int nWidth,int nHeight,bool bSmall);
在C中:每一个函数,即使它不带有返回某种类型的指针,本身有一个入口地址,该地址相当于函数名。尽管函数不是变量,但它在内存中仍有其物理地址,该地址能够赋给指针变量。获取函数方法是:用不带有括号和参数的函数名得到。函数名相当于一个指向其函数入口指针常量。 (注一)
函数指针的说明方法为:
数据类型标志符 (指针变量名)(形参列表);
注1:“函数类型”说明函数的返回类型,由于“()”的优先级高于“*”,所以指针变量名外的括号必不可少,后面的“形参列表”表示指针变量指向的函数所带的参数列表。
例
int func(int x); /* 声明一个函数 */
int (*f) (int x); /* 声明一个函数指针 */
f=func; /* 将func函数的首地址赋给指针f */
赋值时函数func不带括号,也不带参数,func代表函数的首地址。(参见注一)
以下是对回调函数的解译:
cocos2d-x中定义了此种类型:
typedef void (CCObject::*SEL_CallFuncO)(CCObject*);
又定义了一个宏:
#define schedule_selector(_SELECTOR) (SEL_CallFuncO)(&_SELECTOR)
CCObject 是以下所有类的基类.(CCObjectParent, CCObjectRun)
在以下代码中:
// CCObjectParent 成员函数
void CCObjectParent::run()
{
CCObjectRun* pRun = new CCObjectRun();
pRun->run(this, schedule_selector(CCObjectParent::runCallBack)); // 语句一
}
void CCObjectParent::runCallBack(CCObject* )
{
}
/************************/
// CCObjectRun 成员函数
void CCObjectRun ::run(CCObject* pSelectorTarget, SEL_CallFuncO selector)
{
// .................
// 调用返回
if(pSelectorTarget && selector)
{
(pSelectorTarget ->*selector)(this); // 语句二
}
}
对语句一展开:
pRun->run(pObjectB ,(SEL_CallFuncO)(&(CCObjectParent::runCallBack));
对于参数二 (对函数名取地址)其中的理解:
按照&运算符本来的意义:它要求其操作数是一个对象,但函数名不是对象(函数是一个对象),
本来&(CCObjectParent::runCallBack)这样是非法的,但以前有些编译器已经允许这样做,
c/c++标准的制定者出于对象的概念已经有所发展的缘故,也承认了&(CCObjectParent::runCallBack)的合法性。
因此,对于CCObjectParent::runCallBack 和 &(CCObjectParent::runCallBack) 应该这样理解:
CCObjectParent::runCallBack是类成员函数的首地址,它的类型是void (CCObject*),
&(CCObjectParent::runCallBack)表示一个指向类成员函数CCObjectParent::runCallBack这个对象的地址,它的类型是void (CCObjectParent::*)(CCObject*),
因此 CCObjectParent::runCallBack 和 &(CCObjectParent::runCallBack) 所代表的地址值是一样的,但类型不一样。
CCObjectParent::runCallBack是一个函数;
&(CCObjectParent::runCallBack)表达式的值是一个指针!
跟此问题类似的还有对一个数组名取地址。
引用如下:
标准在其rationale中解释了这个问题,摘录如下:
6.5.3.2 Address and indirection operators
Some implementations have not allowed the & operator to be applied to an array or a function.
(The construct was permitted in early versions of C, then later made optional.) The C89 Language
Committee endorsed the construct since it is unambiguous, and since data abstraction is
enhanced by allowing the important & operator to apply uniformly to any addressable entity.